]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #10984 from fbuihuu/tmpfiles-be-more-explicit-with-unsafe-transition
authorLennart Poettering <lennart@poettering.net>
Mon, 10 Dec 2018 11:31:56 +0000 (12:31 +0100)
committerGitHub <noreply@github.com>
Mon, 10 Dec 2018 11:31:56 +0000 (12:31 +0100)
tmpfiles: be more explicit when an unsafe path transition is met

576 files changed:
.dir-locals.el
.lgtm.yml
.travis.yml
.vimrc
README.md
TODO
docs/BLOCK_DEVICE_LOCKING.md [new file with mode: 0644]
docs/CODE_QUALITY.md
docs/CODING_STYLE.md
docs/ENVIRONMENT.md
docs/RELEASE.md
docs/UIDS-GIDS.md
docs/index.md
hwdb/60-sensor.hwdb
hwdb/70-mouse.hwdb
hwdb/ids_parser.py
hwdb/parse_hwdb.py
man/.dir-locals.el
man/daemon.xml
man/machinectl.xml
man/nss-mymachines.xml
man/systemd-analyze.xml
man/systemd-journald.service.xml
man/systemd.mount.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.resource-control.xml
man/systemd.swap.xml
man/systemd.unit.xml
meson.build
po/cs.po
rules/60-block.rules
shell-completion/bash/systemd-analyze
src/activate/activate.c
src/analyze/analyze-security.c [new file with mode: 0644]
src/analyze/analyze-security.h [new file with mode: 0644]
src/analyze/analyze-verify.c
src/analyze/analyze.c
src/analyze/meson.build
src/basic/af-list.c
src/basic/alloc-util.h
src/basic/arphrd-list.c
src/basic/blockdev-util.c
src/basic/btrfs-ctree.h [deleted file]
src/basic/btrfs-util.c
src/basic/btrfs-util.h
src/basic/cap-list.c
src/basic/capability-util.c
src/basic/capability-util.h
src/basic/conf-files.c
src/basic/conf-files.h
src/basic/copy.c
src/basic/copy.h
src/basic/env-file.c [new file with mode: 0644]
src/basic/env-file.h [new file with mode: 0644]
src/basic/errno-list.c
src/basic/escape.h
src/basic/ether-addr-util.c
src/basic/ether-addr-util.h
src/basic/fd-util.c
src/basic/fileio.c
src/basic/fileio.h
src/basic/fs-util.c
src/basic/generate-af-list.sh
src/basic/generate-arphrd-list.sh
src/basic/hash-funcs.c
src/basic/hash-funcs.h
src/basic/hashmap.c
src/basic/hashmap.h
src/basic/hostname-util.c
src/basic/hostname-util.h
src/basic/in-addr-util.c
src/basic/in-addr-util.h
src/basic/locale-util.c
src/basic/locale-util.h
src/basic/macro.h
src/basic/meson.build
src/basic/missing.h
src/basic/missing_audit.h [new file with mode: 0644]
src/basic/missing_btrfs.h [new file with mode: 0644]
src/basic/missing_btrfs_tree.h [new file with mode: 0644]
src/basic/missing_capability.h [new file with mode: 0644]
src/basic/missing_drm.h [new file with mode: 0644]
src/basic/missing_ethtool.h [new file with mode: 0644]
src/basic/missing_fcntl.h [new file with mode: 0644]
src/basic/missing_fib_rules.h [new file with mode: 0644]
src/basic/missing_fou.h [new file with mode: 0644]
src/basic/missing_fs.h [new file with mode: 0644]
src/basic/missing_if_bridge.h [new file with mode: 0644]
src/basic/missing_if_link.h [new file with mode: 0644]
src/basic/missing_if_tunnel.h [new file with mode: 0644]
src/basic/missing_input.h [new file with mode: 0644]
src/basic/missing_keyctl.h [new file with mode: 0644]
src/basic/missing_magic.h [new file with mode: 0644]
src/basic/missing_mman.h [new file with mode: 0644]
src/basic/missing_network.h [new file with mode: 0644]
src/basic/missing_prctl.h [new file with mode: 0644]
src/basic/missing_random.h [new file with mode: 0644]
src/basic/missing_resource.h [new file with mode: 0644]
src/basic/missing_sched.h [new file with mode: 0644]
src/basic/missing_securebits.h [new file with mode: 0644]
src/basic/missing_socket.h [new file with mode: 0644]
src/basic/missing_stat.h [new file with mode: 0644]
src/basic/missing_stdlib.h [new file with mode: 0644]
src/basic/missing_syscall.h
src/basic/missing_timerfd.h [new file with mode: 0644]
src/basic/missing_type.h [new file with mode: 0644]
src/basic/missing_vxcan.h [new file with mode: 0644]
src/basic/mountpoint-util.c [new file with mode: 0644]
src/basic/mountpoint-util.h [new file with mode: 0644]
src/basic/ordered-set.h
src/basic/parse-util.c
src/basic/path-util.c
src/basic/path-util.h
src/basic/process-util.c
src/basic/process-util.h
src/basic/random-util.c
src/basic/rlimit-util.c [moved from src/shared/rlimit-util.c with 94% similarity]
src/basic/rlimit-util.h [moved from src/shared/rlimit-util.h with 96% similarity]
src/basic/rm-rf.c
src/basic/rm-rf.h
src/basic/securebits.h [deleted file]
src/basic/selinux-util.c
src/basic/set.h
src/basic/socket-label.c
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/static-destruct.h
src/basic/terminal-util.c
src/basic/terminal-util.h
src/basic/time-util.c
src/basic/tmpfile-util.c [new file with mode: 0644]
src/basic/tmpfile-util.h [new file with mode: 0644]
src/basic/unit-name.h
src/basic/utf8.h
src/basic/util.c
src/basic/util.h
src/boot/bootctl.c
src/boot/efi/measure.c
src/boot/efi/shim.c
src/boot/efi/shim.h
src/busctl/busctl.c
src/cgtop/cgtop.c
src/core/automount.c
src/core/bpf-devices.c
src/core/bpf-devices.h
src/core/bpf-firewall.c
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c
src/core/dbus-execute.c
src/core/dbus-job.c
src/core/dbus-job.h
src/core/dbus-socket.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/device.c
src/core/execute.c
src/core/execute.h
src/core/job.c
src/core/job.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/locale-setup.c
src/core/machine-id-setup.c
src/core/main.c
src/core/mount-setup.c
src/core/mount.c
src/core/mount.h
src/core/namespace.c
src/core/path.c
src/core/scope.c
src/core/service.c
src/core/shutdown.c
src/core/slice.c
src/core/socket.c
src/core/swap.c
src/core/target.c
src/core/timer.c
src/core/umount.c
src/core/unit-printf.c
src/core/unit-printf.h
src/core/unit.c
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/cryptsetup/cryptsetup-generator.c
src/delta/delta.c
src/environment-d-generator/environment-d-generator.c
src/firstboot/firstboot.c
src/fsck/fsck.c
src/fstab-generator/fstab-generator.c
src/fuzz/fuzz-catalog.c
src/fuzz/fuzz-journald-native-fd.c
src/fuzz/fuzz-journald-stream.c
src/fuzz/fuzz-ndisc-rs.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hostname/hostnamed.c
src/import/export-raw.c
src/import/export-tar.c
src/import/export.c
src/import/import-common.c
src/import/import-common.h
src/import/import-fs.c [new file with mode: 0644]
src/import/import-raw.c
src/import/import-tar.c
src/import/import.c
src/import/importd.c
src/import/meson.build
src/import/org.freedesktop.import1.conf
src/import/pull-common.c
src/import/pull-job.c
src/import/pull-job.h
src/import/pull-raw.c
src/import/pull-tar.c
src/journal-remote/journal-gatewayd.c
src/journal-remote/journal-remote-main.c
src/journal-remote/journal-remote.c
src/journal-remote/journal-remote.h
src/journal-remote/journal-upload.c
src/journal-remote/microhttpd-util.h
src/journal/audit-type.c
src/journal/audit-type.h
src/journal/catalog.c
src/journal/journal-send.c
src/journal/journal-verify.c
src/journal/journalctl.c
src/journal/journald-audit.h
src/journal/journald-native.c
src/journal/journald-stream.c
src/journal/lookup3.c
src/journal/meson.build
src/journal/sd-journal.c
src/journal/test-catalog.c
src/journal/test-compress.c
src/journal/test-journal-enum.c
src/journal/test-journal-match.c
src/journal/test-mmap-cache.c
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/lldp-neighbor.c
src/libsystemd-network/lldp-neighbor.h
src/libsystemd-network/lldp-network.c
src/libsystemd-network/ndisc-router.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/sd-lldp.c
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd/meson.build
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-dump.c
src/libsystemd/sd-bus/bus-error.c
src/libsystemd/sd-bus/bus-error.h
src/libsystemd/sd-bus/bus-internal.c
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-match.c
src/libsystemd/sd-bus/bus-match.h
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-message.h
src/libsystemd/sd-bus/bus-objects.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/bus-track.c
src/libsystemd/sd-bus/bus-type.c
src/libsystemd/sd-bus/bus-type.h
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-benchmark.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-error.c
src/libsystemd/sd-bus/test-bus-marshal.c
src/libsystemd/sd-bus/test-bus-watch-bind.c
src/libsystemd/sd-device/device-monitor.c
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-hwdb/hwdb-util.c
src/libsystemd/sd-id128/id128-util.c
src/libsystemd/sd-id128/id128-util.h
src/libsystemd/sd-login/sd-login.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/rtnl-message.c
src/libsystemd/sd-network/sd-network.c
src/libsystemd/sd-resolve/test-resolve.c
src/locale/keymap-util.c
src/locale/localectl.c
src/locale/localed.c
src/login/inhibit.c
src/login/loginctl.c
src/login/logind-button.c
src/login/logind-button.h
src/login/logind-dbus.c
src/login/logind-inhibit.c
src/login/logind-seat-dbus.c
src/login/logind-seat.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-user-dbus.c
src/login/logind-user.c
src/login/test-inhibit.c
src/login/user-runtime-dir.c
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machine.c
src/machine/machine.h
src/machine/machinectl.c
src/machine/machined-dbus.c
src/machine/machined.c
src/mount/mount-tool.c
src/network/fuzz-netdev-parser.c
src/network/fuzz-network-parser.c
src/network/meson.build
src/network/netdev/bridge.c
src/network/netdev/fou-tunnel.h
src/network/netdev/geneve.c
src/network/netdev/ipvlan.h
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/netdev/tunnel.c
src/network/netdev/tunnel.h
src/network/netdev/vxcan.c
src/network/netdev/vxcan.h
src/network/netdev/vxlan.c
src/network/netdev/wireguard.c
src/network/networkd-address-label.c
src/network/networkd-address-label.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-brvlan.c
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-fdb.c
src/network/networkd-ipv4ll.c
src/network/networkd-ipv6-proxy-ndp.c
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-lldp-tx.c
src/network/networkd-manager.c
src/network/networkd-ndisc.c
src/network/networkd-neighbor.c [new file with mode: 0644]
src/network/networkd-neighbor.h [new file with mode: 0644]
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
src/network/networkd-route.c
src/network/networkd-route.h
src/network/networkd-routing-policy-rule.c
src/network/networkd-routing-policy-rule.h
src/network/networkd.c
src/network/test-routing-policy-rule.c
src/network/wait-online/wait-online.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-network.c
src/nspawn/nspawn-patch-uid.c
src/nspawn/nspawn-patch-uid.h
src/nspawn/nspawn-settings.h
src/nspawn/nspawn-setuid.c
src/nspawn/nspawn.c
src/partition/growfs.c
src/partition/makefs.c
src/portable/portable.c
src/portable/portable.h
src/portable/portablectl.c
src/portable/portabled-bus.c
src/portable/portabled-image-bus.c
src/portable/portabled-image.c
src/portable/portabled.c
src/quotacheck/quotacheck.c
src/rc-local-generator/rc-local-generator.c
src/remount-fs/remount-fs.c
src/resolve/resolvconf-compat.c
src/resolve/resolvectl.c
src/resolve/resolvectl.h
src/resolve/resolved-bus.c
src/resolve/resolved-dns-answer.c
src/resolve/resolved-dns-answer.h
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-search-domain.c
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dns-stream.h
src/resolve/resolved-dns-stub.c
src/resolve/resolved-dns-synthesize.c
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dnssd-bus.c
src/resolve/resolved-dnssd.c
src/resolve/resolved-dnstls-openssl.c
src/resolve/resolved-etc-hosts.c
src/resolve/resolved-link.c
src/resolve/resolved-llmnr.c
src/resolve/resolved-manager.c
src/resolve/resolved-resolv-conf.c
src/resolve/resolved.c
src/resolve/test-dns-packet.c
src/resolve/test-dnssec.c
src/resolve/test-resolved-etc-hosts.c
src/shared/ask-password-api.c
src/shared/blkid-util.h
src/shared/bootspec.c
src/shared/bus-unit-util.c
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/cgroup-show.c
src/shared/cgroup-show.h
src/shared/condition.c
src/shared/conf-parser.c
src/shared/daemon-util.h [new file with mode: 0644]
src/shared/dev-setup.c
src/shared/dev-setup.h
src/shared/dissect-image.c
src/shared/dns-domain.c
src/shared/dns-domain.h
src/shared/env-file-label.c [new file with mode: 0644]
src/shared/env-file-label.h [new file with mode: 0644]
src/shared/exec-util.c
src/shared/fileio-label.c
src/shared/fileio-label.h
src/shared/format-table.c
src/shared/format-table.h
src/shared/generate-ip-protocol-list.sh [moved from src/shared/generate-socket-protocol-list.sh with 100% similarity]
src/shared/generator.c
src/shared/import-util.c
src/shared/install.c
src/shared/ip-protocol-list.c [new file with mode: 0644]
src/shared/ip-protocol-list.h [new file with mode: 0644]
src/shared/ip-protocol-to-name.awk [moved from src/shared/socket-protocol-to-name.awk with 62% similarity]
src/shared/json.c
src/shared/json.h
src/shared/lockfile-util.h
src/shared/logs-show.c
src/shared/machine-image.c
src/shared/machine-image.h
src/shared/machine-pool.c
src/shared/machine-pool.h
src/shared/meson.build
src/shared/mount-util.c [moved from src/basic/mount-util.c with 58% similarity]
src/shared/mount-util.h [moved from src/basic/mount-util.h with 57% similarity]
src/shared/nsflags.c
src/shared/nsflags.h
src/shared/os-util.c
src/shared/output-mode.c
src/shared/output-mode.h
src/shared/pager.c
src/shared/path-lookup.c
src/shared/pretty-print.c
src/shared/pretty-print.h
src/shared/ptyfwd.c
src/shared/ptyfwd.h
src/shared/seccomp-util.c
src/shared/securebits-util.c
src/shared/securebits-util.h
src/shared/serialize.c
src/shared/serialize.h
src/shared/sleep-config.c
src/shared/socket-protocol-list.c [deleted file]
src/shared/socket-protocol-list.h [deleted file]
src/shared/switch-root.c
src/shared/tests.c
src/shared/tmpfile-util-label.c [new file with mode: 0644]
src/shared/tmpfile-util-label.h [new file with mode: 0644]
src/shared/udev-util.c
src/shared/verbs.h
src/sulogin-shell/sulogin-shell.c
src/systemctl/systemctl.c
src/systemd/_sd-common.h
src/systemd/sd-bus.h
src/systemd/sd-event.h
src/systemd/sd-netlink.h
src/systemd/sd-resolve.h
src/sysusers/sysusers.c
src/test/meson.build
src/test/test-acl-util.c
src/test/test-arphrd-list.c
src/test/test-async.c
src/test/test-capability.c
src/test/test-cgroup-mask.c
src/test/test-cgroup.c
src/test/test-chown-rec.c
src/test/test-clock.c
src/test/test-conf-parser.c
src/test/test-copy.c
src/test/test-daemon.c
src/test/test-dev-setup.c [new file with mode: 0644]
src/test/test-dns-domain.c
src/test/test-execute.c
src/test/test-fd-util.c
src/test/test-fdset.c
src/test/test-fileio.c
src/test/test-format-table.c
src/test/test-fs-util.c
src/test/test-glob-util.c
src/test/test-hashmap-plain.c
src/test/test-hostname-util.c
src/test/test-id128.c
src/test/test-ip-protocol-list.c [new file with mode: 0644]
src/test/test-job-type.c
src/test/test-journal-importer.c
src/test/test-locale-util.c
src/test/test-mount-util.c
src/test/test-mountpoint-util.c [new file with mode: 0644]
src/test/test-parse-util.c
src/test/test-path-util.c
src/test/test-path.c
src/test/test-prioq.c
src/test/test-process-util.c
src/test/test-rlimit-util.c
src/test/test-serialize.c
src/test/test-set.c
src/test/test-sigbus.c
src/test/test-socket-util.c
src/test/test-stat-util.c
src/test/test-static-destruct.c [new file with mode: 0644]
src/test/test-systemd-tmpfiles.py
src/test/test-terminal-util.c
src/test/test-tmpfiles.c
src/test/test-umount.c
src/test/test-unit-file.c
src/test/test-user-util.c
src/test/test-util.c
src/test/test-xattr-util.c
src/timedate/timedated.c
src/timesync/timesyncd.c
src/tmpfiles/tmpfiles.c
src/udev/net/ethtool-util.h
src/udev/net/link-config.c
src/udev/udev-builtin-btrfs.c
src/udev/udev-ctrl.c
src/udev/udev-event.c
src/udev/udev-node.c
src/udev/udev-rules.c
src/udev/udevadm-trigger.c
src/udev/udevadm-util.c
src/udev/udevd.c
src/user-sessions/user-sessions.c
src/vconsole/vconsole-setup.c
src/volatile-root/volatile-root.c
test/TEST-25-IMPORT/Makefile [new symlink]
test/TEST-25-IMPORT/test.sh [new file with mode: 0755]
test/TEST-25-IMPORT/testsuite.sh [new file with mode: 0755]
test/fuzz/fuzz-netdev-parser/directives.netdev
test/fuzz/fuzz-network-parser/25-fibrule-port-range.network
test/fuzz/fuzz-network-parser/25-neighbor-section.network [new file with mode: 0644]
test/fuzz/fuzz-network-parser/26-bridge-slave-interface-1.network
test/fuzz/fuzz-network-parser/directives.network
test/fuzz/fuzz-unit-file/directives.service
test/meson.build
test/nomem.slice [new file with mode: 0644]
test/nomemleaf.service [new file with mode: 0644]
test/test-network/conf/25-fibrule-invert.network [new file with mode: 0644]
test/test-network/conf/25-fibrule-port-range.network
test/test-network/conf/25-isatap-tunnel.netdev [new file with mode: 0644]
test/test-network/conf/25-neighbor-section.network [new file with mode: 0644]
test/test-network/conf/26-bridge-slave-interface-1.network
test/test-network/conf/isatap.network [new file with mode: 0644]
test/test-network/systemd-networkd-tests.py
tools/catalog-report.py
tools/gdb-sd_dump_hashmaps.py
tools/generate-gperfs.py
tools/make-directive-index.py
tools/make-index-md.sh
tools/make-man-index.py
tools/make-man-rules.py
tools/xml_helper.py
travis-ci/managers/debian.sh [new file with mode: 0755]
travis-ci/managers/fedora.sh
units/var-lib-machines.mount

index e3d01b28a9790e22943f1f148efe701adc60459b..676d7552312a748ff25f3758d98b265e0fc1cba0 100644 (file)
@@ -2,14 +2,14 @@
 ; A list of (major-mode . ((var1 . value1) (var2 . value2)))
 ; Mode can be nil, which gives default values.
 
-; Note that we set a line width of 119 for .c and XML files, but for everything
+; Note that we set a line width of 109 for .c and XML files, but for everything
 ; else (such as journal catalog files, unit files, README files) we stick to a
 ; more conservative 79 characters.
 
 ; NOTE: If you update this file make sure to update .vimrc and .editorconfig,
 ; too.
 
-((c-mode . ((fill-column . 119)
+((c-mode . ((fill-column . 109)
             (c-basic-offset . 8)
             (eval . (c-set-offset 'substatement-open 0))
             (eval . (c-set-offset 'statement-case-open 0))
@@ -17,7 +17,7 @@
             (eval . (c-set-offset 'arglist-intro '++))
             (eval . (c-set-offset 'arglist-close 0))))
  (nxml-mode . ((nxml-child-indent . 2)
-               (fill-column . 119)))
+               (fill-column . 109)))
  (meson-mode . ((meson-indent-basic . 8)))
  (sh-mode . ((sh-basic-offset . 8)
              (sh-indentation . 8)))
index 37f9c4335c2e127b98b2e98c1a08db2f3e622cb4..5948d8c2bc0d7fc7f941cd62c843f4bd6b7ed887 100644 (file)
--- a/.lgtm.yml
+++ b/.lgtm.yml
@@ -8,3 +8,6 @@ extraction:
     after_prepare:
       - pip3 install meson
       - export PATH="$HOME/.local/bin/:$PATH"
+  python:
+    python_setup:
+      version: 3
index ce5d099660a7fdb84adb96868edbe4ae1294034c..f50731fe3fa56e900aba6cec40b3740318a66e4a 100644 (file)
@@ -17,10 +17,10 @@ stages:
 jobs:
     include:
         - stage: Build & test
-          name: Fedora Rawhide
+          name: Fedora Latest
           language: bash
           env:
-              - FEDORA_RELEASE="rawhide"
+              - FEDORA_RELEASE="latest"
               - CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
               - DOCKER_EXEC="docker exec -ti $CONT_NAME"
           before_install:
@@ -36,10 +36,10 @@ jobs:
           after_script:
               - $CI_MANAGERS/fedora.sh CLEANUP
 
-        - name: Fedora Rawhide (ASan+UBSan)
+        - name: Fedora Latest (ASan+UBSan)
           language: bash
           env:
-              - FEDORA_RELEASE="rawhide"
+              - FEDORA_RELEASE="latest"
               - CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
               - DOCKER_EXEC="docker exec -ti $CONT_NAME"
           before_install:
@@ -54,6 +54,60 @@ jobs:
           after_script:
               - $CI_MANAGERS/fedora.sh CLEANUP
 
+        - name: Fedora Latest (clang)
+          language: bash
+          env:
+              - FEDORA_RELEASE="latest"
+              - CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
+              - DOCKER_EXEC="docker exec -ti $CONT_NAME"
+          before_install:
+              - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+              - docker --version
+          install:
+              - $CI_MANAGERS/fedora.sh SETUP
+          script:
+              - set -e
+              - $CI_MANAGERS/fedora.sh RUN_CLANG
+              - set +e
+          after_script:
+              - $CI_MANAGERS/fedora.sh CLEANUP
+
+        - name: Fedora Latest (clang ASan+UBSan)
+          language: bash
+          env:
+              - FEDORA_RELEASE="latest"
+              - CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
+              - DOCKER_EXEC="docker exec -ti $CONT_NAME"
+          before_install:
+              - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+              - docker --version
+          install:
+              - $CI_MANAGERS/fedora.sh SETUP
+          script:
+              - set -e
+              - $CI_MANAGERS/fedora.sh RUN_CLANG_ASAN
+              - set +e
+          after_script:
+              - $CI_MANAGERS/fedora.sh CLEANUP
+
+        - name: Debian Testing
+          language: bash
+          env:
+              - DEBIAN_RELEASE="testing"
+              - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
+              - DOCKER_EXEC="docker exec -ti $CONT_NAME"
+          before_install:
+              - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+              - docker --version
+          install:
+              - $CI_MANAGERS/debian.sh SETUP
+          script:
+              - set -e
+              - $CI_MANAGERS/debian.sh RUN
+              - set +e
+          after_script:
+              - $CI_MANAGERS/debian.sh CLEANUP
+
         - stage: Coverity
           language: bash
           env:
diff --git a/.vimrc b/.vimrc
index 284bf88494c574f0aefb4f76650b5a1320af4489..a62546d8e2aa8a834ba2f3ecdab2069b8c5958cb 100644 (file)
--- a/.vimrc
+++ b/.vimrc
@@ -4,7 +4,7 @@
 " You should consider setting 'set secure' as well, which is highly
 " recommended!
 
-" Note that we set a line width of 119 for .c and XML files, but for everything
+" Note that we set a line width of 109 for .c and XML files, but for everything
 " else (such as journal catalog files, unit files, README files) we stick to a
 " more conservative 79 characters.
 
@@ -16,5 +16,5 @@ set shiftwidth=8
 set expandtab
 set makeprg=GCC_COLORS=\ make
 set tw=79
-au BufRead,BufNewFile *.xml set tw=119 shiftwidth=2 smarttab
-au FileType c set tw=119
+au BufRead,BufNewFile *.xml set tw=109 shiftwidth=2 smarttab
+au FileType c set tw=109
index 7d6e0d99a802116403ad7fa1a1d0b77a7655dd39..72484f620c1acfeff010b18ed80bab2f9e5dce0e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -2,11 +2,12 @@
 
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-issues.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-issues-small.svg" alt="Count of open issues over time"></a>
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests-small.svg" alt="Count of open pull requests over time"></a>
-[![Build Status](https://semaphoreci.com/api/v1/projects/28a5a3ca-3c56-4078-8b5e-7ed6ef912e14/443470/shields_badge.svg)](https://semaphoreci.com/systemd/systemd)<br/>
+[![Semaphore CI Build Status](https://semaphoreci.com/api/v1/projects/28a5a3ca-3c56-4078-8b5e-7ed6ef912e14/443470/shields_badge.svg)](https://semaphoreci.com/systemd/systemd)<br/>
 [![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
-[![Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
-[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)
+[![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
+[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
+[![CentOS CI Build Status](https://ci.centos.org/buildStatus/icon?job=systemd-pr-build)](https://ci.centos.org/job/systemd-pr-build/)
 
 ## Details
 
diff --git a/TODO b/TODO
index 97681c421f166a107627630a01e04762f0fda44f..3a4eac4b2c0b15abdb54841562cb7f5b8dbd9f4a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -23,8 +23,20 @@ Janitorial Clean-ups:
 
 Features:
 
+* when importing an fs tree with machined, optionally apply userns-rec-chown
+
+* when importing an fs tree with machined, complain if image is not an OS
+
 * when we fork off generators and such, lower LIMIT_NOFILE soft limit to 1K
 
+* Maybe introduce a helper safe_exec() or so, which is to execve() which
+  safe_fork() is to fork(). And then make revert the RLIMIT_NOFILE soft limit
+  to 1K implicitly, unless explicitly opted-out.
+
+* rework seccomp/nnp logic that that even if User= is used in combination with
+  a seccomp option we don't have to set NNP. For that, change uid first whil
+  keeping CAP_SYS_ADMIN, then apply seccomp, the drop cap.
+
 * add a concept for automatically loading per-unit secrets off disk and
   inserting them into the kernel keyring. Maybe SecretsDirectory= similar to
   ConfigurationDirectory=.
@@ -41,11 +53,17 @@ Features:
 
 * bootctl,sd-boot: actually honour the "architecture" key
 
+* when a socket unit is spawned with an AF_UNIX path in /var/run, complain and
+  patch it to use /run instead
+
 * consider splitting out all temporary file creation APIs (we have so many in
   fileio.h and elsewhere!) into a new util file of its own.
 
 * set memory.oom.group in cgroupsv2 for all leaf cgroups (kernel v4.19+)
 
+* add a new syscall group "@esoteric" for more esoteric stuff such as bpf() and
+  usefaultd() and make systemd-analyze check for it.
+
 * drop umask() calls and suchlike from our generators, pid1 should set things up correctly anyway
 
 * paranoia: whenever we process passwords, call mlock() on the memory
@@ -92,6 +110,29 @@ Features:
 
 * bootspec.c: also enumerate EFI unified kernel images.
 
+* maybe set a special xattr on cgroups that have delegate=yes set, to make it
+  easy to mark cut points
+
+* introduce an option (or replacement) for "systemctl show" that outputs all
+  properties as JSON, similar to busctl's new JSON output. In contrast to that
+  it should skip the variant type string though.
+
+* augment CODE_FILE=, CODE_LINE= with something like CODE_BASE= or so which
+  contains some identifier for the project, which allows us to include
+  clickable links to source files generating these log messages. The identifier
+  could be some abberviated URL prefix or so (taking inspiration from Go
+  imports). For example, for systemd we could use
+  CODE_BASE=github.com/systemd/systemd/blob/98b0b1123cc or so which is
+  sufficient to build a link by prefixing "http://" and suffixing the
+  CODE_FILE.
+
+* when outputting log data with journalctl and the log data includes references
+  to configuration files (CONFIG_FILE=), create a clickable link for it.
+
+* Augment MESSAGE_ID with MESSAGE_BASE, in a similar fashion so that we can
+  make clickable links from log messages carrying a MESSAGE_ID, that lead to
+  some explanatory text online.
+
 * maybe extend .path units to expose fanotify() per-mount change events
 
 * Add a "systemctl list-units --by-slice" mode or so, which rearranges the
@@ -235,8 +276,7 @@ Features:
   the runtime dir as we maintain for the fdstore: i.e. keep it around as long
   as the unit is running or has a job queued.
 
-* support projid-based quota in machinectl for containers, and then drop
-  implicit btrfs loopback magic in machined
+* support projid-based quota in machinectl for containers
 
 * Add NetworkNamespacePath= to specify a path to a network namespace
 
@@ -265,9 +305,6 @@ Features:
 * beef up pam_systemd to take unit file settings such as cgroups properties as
   parameters
 
-* a new "systemd-analyze security" tool outputting a checklist of security
-  features a service does and does not implement
-
 * maybe hook of xfs/ext4 quotactl() with services? i.e. automatically manage
   the quota of a the user indicated in User= via unit file settings, like the
   other resource management concepts. Would mix nicely with DynamicUser=1. Or
@@ -881,9 +918,6 @@ Features:
   - "machinectl commit" that takes a writable snapshot of a tree, invokes a
     shell in it, and marks it read-only after use
 
-* importd:
-  - generate a nice warning if mkfs.btrfs is missing
-
 * cryptsetup:
   - cryptsetup-generator: allow specification of passwords in crypttab itself
   - support rd.luks.allow-discards= kernel cmdline params in cryptsetup generator
diff --git a/docs/BLOCK_DEVICE_LOCKING.md b/docs/BLOCK_DEVICE_LOCKING.md
new file mode 100644 (file)
index 0000000..ceb060c
--- /dev/null
@@ -0,0 +1,63 @@
+# Locking Block Device Access
+
+*TL;DR: Use BSD file locks
+[(`flock(2)`)](http://man7.org/linux/man-pages/man2/flock.2.html) on block
+device nodes to synchronize access for partitioning and file system formatting
+tools.*
+
+`systemd-udevd` probes all block devices showing up for file system superblock
+and partition table information (utilizing `libblkid`). If another program
+concurrently modifies a superblock or partition table this probing might be
+affected, which is bad in itself, but also might in turn result in undesired
+effects in programs subscribing to `udev` events.
+
+Applications manipulating a block device can temporarily stop `systemd-udevd`
+from processing rules on it — and thus bar it from probing the device — by
+taking a BSD file lock on the block device node. Specifically, whenever
+`systemd-udevd` starts processing a block device it takes a `LOCK_SH|LOCK_NB`
+lock using [`flock(2)`](http://man7.org/linux/man-pages/man2/flock.2.html) on
+the main block device (i.e. never on any partition block device, but on the
+device the partition belongs to). If this lock cannot be taken (i.e. `flock()`
+returns `EBUSY`), it refrains from processing the device. If it manages to take
+the lock it is kept for the entire time the device is processed.
+
+Note that `systemd-udevd` also watches all block device nodes it manages for
+`inotify()` `IN_CLOSE` events: whenever such an event is seen, this is used as
+trigger to re-run the rule-set for the device.
+
+These two concepts allow tools such as disk partitioners or file system
+formatting tools to safely and easily take exclusive ownership of a block
+device while operating: before starting work on the block device, they should
+take an `LOCK_EX` lock on it. This has two effects: first of all, in case
+`systemd-udevd` is still processing the device the tool will wait for it to
+finish. Second, after the lock is taken, it can be sure that that
+`systemd-udevd` will refrain from processing the block device, and thus all
+other client applications subscribed to it won't get device notifications from
+potentially half-written data either. After the operation is complete the
+partitioner/formatter can simply close the device node. This has two effects:
+it implicitly releases the lock, so that `systemd-udevd` can process events on
+the device node again. Secondly, it results an `IN_CLOSE` event, which causes
+`systemd-udevd` to immediately re-process the device — seeing all changes the
+tool made — and notify subscribed clients about it.
+
+Besides synchronizing block device access between `systemd-udevd` and such
+tools this scheme may also be used to synchronize access between those tools
+themselves. However, do note that `flock()` locks are advisory only. This means
+if one tool honours this scheme and another tool does not, they will of course
+not be synchronized properly, and might interfere with each other's work.
+
+Note that the file locks follow the usual access semantics of BSD locks: since
+`systemd-udevd` never writes to such block devices it only takes a `LOCK_SH`
+*shared* lock. A program intending to make changes to the block device should
+take a `LOCK_EX` *exclusive* lock instead. For further details, see the
+`flock(2)` man page.
+
+And please keep in mind: BSD file locks (`flock()`) and POSIX file locks
+(`lockf()`, `F_SETLK`, …) are different concepts, and in their effect
+orthogonal. The scheme discussed above uses the former and not the latter,
+because these types of locks more closely match the required semantics.
+
+Summarizing: it is recommended to take `LOCK_EX` BSD file locks when
+manipulating block devices in all tools that change file system block devices
+(`mkfs`, `fsck`, …) or partition tables (`fdisk`, `parted`, …), right after
+opening the node.
index e673ad58ad9671d5196f15427af23e3a630548f2..be0e13f6535ec1ba01d4974422b3f4ac5798fb38 100644 (file)
@@ -57,8 +57,8 @@ available functionality:
     automatically enable a git commit hook that ensures whitespace cleanliness.
 
 14. [LGTM](https://lgtm.com/) analyzes every commit pushed to master. The list
-    of active alerts can be found at
-    https://lgtm.com/projects/g/systemd/systemd/alerts/?mode=list.
+    of active alerts can be found
+    [here](https://lgtm.com/projects/g/systemd/systemd/alerts/?mode=list).
 
 Access to Coverity and oss-fuzz reports is limited. Please reach out to the
 maintainers if you need access.
index 81a10eb88b455e83d795be25abf79a1da2c727a2..a91e119c4a9a5e8e2c149ea3275440c8a812f5f1 100644 (file)
@@ -1,4 +1,4 @@
-# Coding style
+# Coding Style
 
 - 8ch indent, no tabs, except for files in `man/` which are 2ch indent,
   and still no tabs.
@@ -11,7 +11,7 @@
 
 - Don't break code lines too eagerly. We do **not** force line breaks at 80ch,
   all of today's screens should be much larger than that. But then again, don't
-  overdo it, ~119ch should be enough really. The `.editorconfig`, `.vimrc` and
+  overdo it, ~109ch should be enough really. The `.editorconfig`, `.vimrc` and
   `.dir-locals.el` files contained in the repository will set this limit up for
   you automatically, if you let them (as well as a few other things).
 
index 3e61ea51e7068725beb0e621d0caa7ab87c74eea..e965cb885a312c114e776e11f511f38b947fb74b 100644 (file)
@@ -46,9 +46,14 @@ All tools:
   are understood, too (us, ms, s, min, h, d, w, month, y). If it is not set or set
   to 0, then the built-in default is used.
 
-* `$SYSTEMD_MEMPOOL=0` — if set the internal memory caching logic employed by
+* `$SYSTEMD_MEMPOOL=0` — if set, the internal memory caching logic employed by
   hash tables is turned off, and libc malloc() is used for all allocations.
 
+* `$SYSTEMD_EMOJI=0` — if set, tools such as "systemd-analyze security" will
+  not output graphical smiley emojis, but ASCII alternatives instead. Note that
+  this only controls use of Unicode emoji glyphs, and has no effect on other
+  Unicode glyphs.
+
 systemctl:
 
 * `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus
index 2807667a30b4f20ce75960ff08a4c858990ab9e8..11794aae63974bdbad45edc26e7c93a535f216f5 100644 (file)
@@ -1,4 +1,4 @@
-# Steps to a successful release
+# Steps to a Successful Release
 
 1. Add all items to NEWS
 2. Update the contributors list in NEWS ("make git-contrib")
index 77554913198a76e9282b57364f133ec301e3668d..c59fefc5cd62960d6026b7d5c3631b5df118d7e6 100644 (file)
@@ -1,4 +1,4 @@
-# Users, Groups, UIDs and GIDs on `systemd` systems
+# Users, Groups, UIDs and GIDs on `systemd` Systems
 
 Here's a summary of the requirements `systemd` (and Linux) make on UID/GID
 assignments and their ranges.
index e851f1b7ce780ffdb689d408a4da882c0c167133..f27aeaad2bd03d0fa2d197e95da0b560afe0fc01 100644 (file)
@@ -1,18 +1,19 @@
 # systemd Documentation
 
 * [Automatic Boot Assessment](https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT)
+* [Locking Block Device Access](https://systemd.io/BLOCK_DEVICE_LOCKING)
 * [The Boot Loader Interface](https://systemd.io/BOOT_LOADER_INTERFACE)
 * [The Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION)
 * [Control Group APIs and Delegation](https://systemd.io/CGROUP_DELEGATION)
-* [The systemd Community Conduct Guidelines](https://systemd.io/CODE_OF_CONDUCT)
+* [The systemd Community Conduct Guidelines](https://github.com/systemd/systemd/blob/master/docs/CODE_OF_CONDUCT.md)
 * [Code Quality Tools](https://systemd.io/CODE_QUALITY)
-* [Coding style](https://systemd.io/CODING_STYLE)
-* [Contributing](https://systemd.io/CONTRIBUTING)
+* [Coding Style](https://systemd.io/CODING_STYLE)
+* [Contributing](https://github.com/systemd/systemd/blob/master/docs/CONTRIBUTING.md)
 * [Porting systemd To New Distributions](https://systemd.io/DISTRO_PORTING)
 * [Known Environment Variables](https://systemd.io/ENVIRONMENT)
 * [Hacking on systemd](https://systemd.io/HACKING)
 * [Portable Services Introduction](https://systemd.io/PORTABLE_SERVICES)
-* [Steps to a successful release](https://systemd.io/RELEASE)
+* [Steps to a Successful Release](https://systemd.io/RELEASE)
 * [What settings are currently available for transient units?](https://systemd.io/TRANSIENT-SETTINGS)
 * [Notes for Translators](https://systemd.io/TRANSLATORS)
-* [Users, Groups, UIDs and GIDs on `systemd` systems](https://systemd.io/UIDS-GIDS)
+* [Users, Groups, UIDs and GIDs on `systemd` Systems](https://systemd.io/UIDS-GIDS)
index 9925175e2914fc1d932fc624cffab8038f2c8ec1..c0306bd3ab81d969c8d9441b123b01db8ef65fb4 100644 (file)
@@ -401,6 +401,16 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22
 sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1014:bd10/24/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
+# Point of View TAB-P1005W-232 (v2.0)
+sensor:modalias:acpi:KIOX000A*:dmi:*:rvnPOV:rnI102A:*
+ ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
+
+#########################################
+# Prowise
+#########################################
+sensor:modalias:acpi:SMO8500*:dmi:*:svnProwise:pnPT301:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+
 #########################################
 # Teclast
 #########################################
index 5002d09228452a8c0b3b54e61809ccd0eeca3d47..037518a7047b1807cc97c4af53c288db8bcc4306 100644 (file)
@@ -300,9 +300,9 @@ mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:
 mouse:usb:v17efp6019:name:Logitech Lenovo USB Optical Mouse:
  MOUSE_DPI=1000@166
 
-# ThinkPad USB Laser Mouse
-mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse:
- MOUSE_DPI=1200@125
+# Lenovo USB mouse model MO28UOL
+mouse:usb:v04b3p310c:name:USB Optical Mouse:
+ MOUSE_DPI=400@142
 
 # Lenovo Precision USB Mouse
 mouse:usb:v17efp6050:name:Lenovo Precision USB Mouse:
@@ -314,6 +314,9 @@ mouse:usb:v17efp601d:name:Primax Lenovo Laser Mouse:
 mouse:usb:v17efp6045:name:Lenovo USB Laser Mouse:
  MOUSE_DPI=1600@125
 
+# ThinkPad USB Laser Mouse
+mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse:
+ MOUSE_DPI=1200@125
 
 ##########################################
 # Logitech
@@ -468,10 +471,6 @@ mouse:usb:v046dpc401:name:Logitech USB-PS/2 Trackball:
 mouse:usb:v046dpc501:name:Logitech USB Receiver:
  MOUSE_DPI=800@63
 
-# Lenovo USB mouse model MO28UOL
-mouse:usb:v04b3p310c:name:USB Optical Mouse:
- MOUSE_DPI=400@142
-
 # Logitech USB-PS/2 M-BZ96C
 mouse:usb:v046dpc045:name:Logitech USB-PS/2 Optical Mouse:
  MOUSE_DPI=600@125
index c80d22258a35fd675368a9a3b18754c668ec5a49..61ca0ca6e05e24accf9404bed9297075fabc51c6 100755 (executable)
@@ -17,7 +17,6 @@ TAB = White('\t', exact=1).suppress()
 COMMENTLINE = pythonStyleComment + EOL
 EMPTYLINE = LineEnd()
 text_eol = lambda name: Regex(r'[^\n]+')(name) + EOL
-# text_eol = lambda name: Word(printables + ' ' + '®üäßçõãİó ×²⁶´‐“\u200E\u200B')(name) + EOL
 
 def klass_grammar():
     klass_line = Literal('C ').suppress() + NUM2('klass') + text_eol('text')
index 4900a2577871cc9f225d16af44c1b849c248dd20..d84fba2221ade7a8ac3049a16a9224636ed18dca 100755 (executable)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
-# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
-#  SPDX-License-Identifier: MIT
+# SPDX-License-Identifier: MIT
 #
 # This file is distributed under the MIT license, see below.
 #
@@ -30,8 +29,7 @@ import sys
 import os
 
 try:
-    from pyparsing import (Word, White, Literal, ParserElement, Regex,
-                           LineStart, LineEnd,
+    from pyparsing import (Word, White, Literal, ParserElement, Regex, LineEnd,
                            OneOrMore, Combine, Or, Optional, Suppress, Group,
                            nums, alphanums, printables,
                            stringEnd, pythonStyleComment, QuotedString,
index 6115b4e8cf9be0595c3f0a537b10c18ae65773fa..c252bd370354a151330a72fa93cd29df78aef24b 100644 (file)
@@ -7,7 +7,7 @@
             (eval . (c-set-offset 'arglist-intro '++))
             (eval . (c-set-offset 'arglist-close 0))))
  (nxml-mode . ((nxml-child-indent . 2)
-               (fill-column . 119)))
+               (fill-column . 109)))
  (meson-mode . ((meson-indent-basic . 8)))
  (nil . ((indent-tabs-mode . nil)
          (tab-width . 8)
index 36c7c09db18e58bbd82d30a2a26cbb6dc5903a12..7724bb4e08d8efa25008bd9d0cd051b010c9f339 100644 (file)
@@ -593,7 +593,7 @@ AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])</p
       <citerefentry project='die-net'><refentrytitle>automake</refentrytitle><manvolnum>1</manvolnum></citerefentry>-based
       projects:</para>
 
-      <programlisting>DISTCHECK_CONFIGURE_FLAGS = \
+      <programlisting>AM_DISTCHECK_CONFIGURE_FLAGS = \
   --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)</programlisting>
 
       <para>Finally, unit files should be installed in the system with an automake excerpt like the following:</para>
index 670205033b7ab13c20d3dc8fd93bafaaa61dabdd..95823eb413ef65b96dd126bc2871d8a781205eb0 100644 (file)
       top-level directories <filename>/usr</filename>,
       <filename>/etc</filename>, and so on.</para></listitem>
 
-      <listitem><para>btrfs subvolumes containing OS trees, similar to
-      normal directory trees.</para></listitem>
+      <listitem><para>btrfs subvolumes containing OS trees, similar to regular directory trees.</para></listitem>
 
-      <listitem><para>Binary "raw" disk images containing MBR or GPT
-      partition tables and Linux file system partitions.</para></listitem>
+      <listitem><para>Binary "raw" disk image files containing MBR or GPT partition tables and Linux file
+      systems.</para></listitem>
+
+      <listitem><para>Similarly, block devices containing MBR or GPT partition tables and file systems.</para></listitem>
 
       <listitem><para>The file system tree of the host OS itself.</para></listitem>
     </itemizedlist>
         units. If the size limit shall be disabled, specify
         <literal>-</literal> as size.</para>
 
-        <para>Note that per-container size limits are only supported
-        on btrfs file systems. Also note that, if
-        <command>set-limit</command> is invoked without an image
-        parameter, and <filename>/var/lib/machines</filename> is
-        empty, and the directory is not located on btrfs, a btrfs
-        loopback file is implicitly created as
-        <filename>/var/lib/machines.raw</filename> with the given
-        size, and mounted to
-        <filename>/var/lib/machines</filename>. The size of the
-        loopback may later be readjusted with
-        <command>set-limit</command>, as well. If such a
-        loopback-mounted <filename>/var/lib/machines</filename>
-        directory is used, <command>set-limit</command> without an image
-        name alters both the quota setting within the file system as
-        well as the loopback file and file system size
-        itself.</para></listitem>
+        <para>Note that per-container size limits are only supported on btrfs file systems.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         image is read from standard input, in which case the second
         argument is mandatory.</para>
 
-        <para>Both <command>pull-tar</command> and <command>pull-raw</command>
-        will resize <filename>/var/lib/machines.raw</filename> and the
-        filesystem therein as necessary. Optionally, the
-        <option>--read-only</option> switch may be used to create a
-        read-only container or VM image. No cryptographic validation
-        is done when importing the images.</para>
+        <para>Optionally, the <option>--read-only</option> switch may be used to create a read-only container or VM
+        image. No cryptographic validation is done when importing the images.</para>
 
         <para>Much like image downloads, ongoing imports may be listed
         with <command>list-transfers</command> and aborted with
         <command>cancel-transfer</command>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><command>import-fs</command> <replaceable>DIRECTORY</replaceable> [<replaceable>NAME</replaceable>]</term>
+
+        <listitem><para>Imports a container image stored in a local directory into
+        <filename>/var/lib/machines/</filename>, operates similar to <command>import-tar</command> or
+        <command>import-raw</command>, but the first argument is the source directory. If supported, this command will
+        create btrfs snapshot or subvolume for the new image.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><command>export-tar</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
         <term><command>export-raw</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
     <filename>/var/lib/machines/</filename> to make them available for
     control with <command>machinectl</command>.</para>
 
-    <para>Note that some image operations are only supported,
-    efficient or atomic on btrfs file systems. Due to this, if the
-    <command>pull-tar</command>, <command>pull-raw</command>,
-    <command>import-tar</command>, <command>import-raw</command> and
-    <command>set-limit</command> commands notice that
-    <filename>/var/lib/machines</filename> is empty and not located on
-    btrfs, they will implicitly set up a loopback file
-    <filename>/var/lib/machines.raw</filename> containing a btrfs file
-    system that is mounted to
-    <filename>/var/lib/machines</filename>. The size of this loopback
-    file may be controlled dynamically with
-    <command>set-limit</command>.</para>
+    <para>Note that some image operations are only supported, efficient or atomic on btrfs file systems.</para>
 
     <para>Disk images are understood by
     <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
index a0a0f99684dd35fa5446da0b472b60546911e845..5742d89779cb591473371eb15dc9d8badbbb1ac1 100644 (file)
     <para><command>nss-mymachines</command> is a plug-in module for the GNU Name Service Switch (NSS) functionality of
     the GNU C Library (<command>glibc</command>), providing hostname resolution for the names of containers running
     locally that are registered with
-    <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.  The
+    <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. The
     container names are resolved to the IP addresses of the specific container, ordered by their scope. This
-    functionality only applies to containers using network namespacing.</para>
-
-    <para>The module also resolves user and group IDs used by containers to user and group names indicating the
-    container name, and back. This functionality only applies to containers using user namespacing.</para>
+    functionality only applies to containers using network namespacing (see the description of
+    <option>--private-network</option> in
+    <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>).
+    Note that the name that is resolved is the one registered with <command>systemd-machined</command>, which
+    may be different than the hostname configured inside of the container.</para>
+
+    <para>The module also provides name resolution for user and group identifiers mapped to containers. All names from
+    the range allocated to a given container <replaceable>container</replaceable> are exposed on the host as
+    <literal>vu-<replaceable>container</replaceable>-<replaceable>uid</replaceable></literal> and
+    <literal>vg-<replaceable>container</replaceable>-<replaceable>gid</replaceable></literal> (see example below). This
+    functionality only applies to containers using user namespacing (see the description of
+    <option>--private-users</option> in
+    <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
 
     <para>To activate the NSS module, add <literal>mymachines</literal> to the lines starting with
     <literal>hosts:</literal>, <literal>passwd:</literal> and <literal>group:</literal> in
@@ -53,7 +62,7 @@
   </refsect1>
 
   <refsect1>
-    <title>Example</title>
+    <title>Configuration in <filename>/etc/nsswitch.conf</filename></title>
 
     <para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables
     <command>nss-mymachines</command> correctly:</para>
@@ -75,11 +84,74 @@ netgroup:       nis</programlisting>
 
   </refsect1>
 
+  <refsect1>
+    <title>Mappings provided by <filename>nss-mymachines</filename></title>
+
+    <para>The container <literal>rawhide</literal> is spawned using
+    <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>:
+    </para>
+
+    <programlisting># systemd-nspawn -M rawhide --boot --network-veth --private-users=pick
+Spawning container rawhide on /var/lib/machines/rawhide.
+Selected user namespace base 20119552 and range 65536.
+...
+
+$ machinectl --max-addresses=3
+MACHINE CLASS     SERVICE        OS     VERSION ADDRESSES
+rawhide container systemd-nspawn fedora 30      169.254.40.164 fe80::94aa:3aff:fe7b:d4b9
+
+$ getent passwd vu-rawhide-0 vu-rawhide-81
+vu-rawhide-0:*:20119552:65534:vu-rawhide-0:/:/sbin/nologin
+vu-rawhide-81:*:20119633:65534:vu-rawhide-81:/:/sbin/nologin
+
+$ getent group vg-rawhide-0 vg-rawhide-81
+vg-rawhide-0:*:20119552:
+vg-rawhide-81:*:20119633:
+
+$ ps -o user:15,pid,tty,command -e|grep '^vu-rawhide'
+vu-rawhide-0      692 ?        /usr/lib/systemd/systemd
+vu-rawhide-0      731 ?        /usr/lib/systemd/systemd-journald
+vu-rawhide-192    734 ?        /usr/lib/systemd/systemd-networkd
+vu-rawhide-193    738 ?        /usr/lib/systemd/systemd-resolved
+vu-rawhide-0      742 ?        /usr/lib/systemd/systemd-logind
+vu-rawhide-81     744 ?        /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
+vu-rawhide-0      746 ?        /usr/sbin/sshd -D ...
+vu-rawhide-0      752 ?        /usr/lib/systemd/systemd --user
+vu-rawhide-0      753 ?        (sd-pam)
+vu-rawhide-0     1628 ?        login -- zbyszek
+vu-rawhide-1000  1630 ?        /usr/lib/systemd/systemd --user
+vu-rawhide-1000  1631 ?        (sd-pam)
+vu-rawhide-1000  1637 pts/8    -zsh
+
+$ ping -c1 rawhide
+PING rawhide(fe80::94aa:3aff:fe7b:d4b9%ve-rawhide (fe80::94aa:3aff:fe7b:d4b9%ve-rawhide)) 56 data bytes
+64 bytes from fe80::94aa:3aff:fe7b:d4b9%ve-rawhide (fe80::94aa:3aff:fe7b:d4b9%ve-rawhide): icmp_seq=1 ttl=64 time=0.045 ms
+...
+$ ping -c1 -4 rawhide
+PING rawhide (169.254.40.164) 56(84) bytes of data.
+64 bytes from 169.254.40.164 (169.254.40.164): icmp_seq=1 ttl=64 time=0.064 ms
+...
+
+# machinectl shell rawhide /sbin/ip a
+Connected to machine rawhide. Press ^] three times within 1s to exit session.
+1: lo: &lt;LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    ...
+2: host0@if21: &lt;BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether 96:aa:3a:7b:d4:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 169.254.40.164/16 brd 169.254.255.255 scope link host0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::94aa:3aff:fe7b:d4b9/64 scope link
+       valid_lft forever preferred_lft forever
+Connection to machine rawhide terminated.
+</programlisting>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
index 15e95b0c8f5be9788c25dc5dc3292533614bd3f7..7becf0133e9eaa670fbfee292bd6af86b5c13bce 100644 (file)
       <arg choice="plain">timespan</arg>
       <arg choice="plain" rep="repeat"><replaceable>SPAN</replaceable></arg>
     </cmdsynopsis>
+    <cmdsynopsis>
+      <command>systemd-analyze</command>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
+      <arg choice="plain">security</arg>
+      <arg choice="plain" rep="repeat"><replaceable>UNIT</replaceable></arg>
+    </cmdsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
@@ -263,6 +269,29 @@ NAutoVTs=8
     The time span should adhere to the same syntax documented in <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
     Values without associated magnitudes are parsed as seconds.</para>
 
+    <para><command>systemd-analyze security</command> analyzes the security and sandboxing settings of one or more
+    specified service units. If at least one unit name is specified the security settings of the specified service
+    units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
+    long-running service units are inspected and a terse table with results shown. The command checks for various
+    security-related service settings, assigning each a numeric "exposure level" value, depending on how important a
+    setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range
+    0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied
+    sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only
+    analyzes the per-service security features systemd itself implements. This means that any additional security
+    mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should
+    not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the
+    service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels
+    do indicate however that most likely the service might benefit from additional settings applied to them. Please
+    note that many of the security and sandboxing settings individually can be circumvented — unless combined with
+    others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing
+    options can be undone by the service code itself. Due to that is essential that each service uses the most
+    comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these
+    combinations and relationships between the settings, but not all. Also note that the security and sandboxing
+    settings analyzed here only apply to the operations executed by the service code itself. If a service has access to
+    an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same
+    restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is
+    not validated too.</para>
+
     <para>If no command is passed, <command>systemd-analyze
     time</command> is implied.</para>
 
index f0f03a29b21fa47d08eeb9bf10431b7230faf21e..9167993012a2f4e4248d4601825956c353453a97 100644 (file)
@@ -52,7 +52,7 @@
 
       <listitem><para>Structured system log messages via the native
       Journal API, see
-      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry></para></listitem>
+      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry></para></listitem>
 
       <listitem><para>Standard output and standard error of service units. For further details see
       below.</para></listitem>
@@ -303,7 +303,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
       <citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <command>pydoc systemd.journal</command>
     </para>
   </refsect1>
index daee201eeb41d34a693cbc3aa0faf6848337b10f..abd43ee68481c35268922cb2f767cb4e0e8289fe 100644 (file)
         for details.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
+      <varlistentry id='device-timeout'>
         <term><option>x-systemd.device-timeout=</option></term>
 
         <listitem><para>Configure how long systemd should wait for a
       <varlistentry>
         <term><option>x-systemd.makefs</option></term>
 
-        <listitem><para>The file system or swap structure will be initialized
+        <listitem><para>The file system will be initialized
         on the device. If the device is not "empty", i.e. it contains any signature,
         the operation will be skipped. It is hence expected that this option
         remains set even after the device has been initalized.</para>
index f17a6a961905a81aadc794d282e7beba1cbe8d12..67ccc66dd8ed09ffd17378504c23b6140453ece9 100644 (file)
           applicable to SIT tunnels.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>ISATAP=</varname></term>
+        <listitem>
+          <para>Takes a boolean. If set, configures the tunnel as Intra-Site Automatic Tunnel Addressing Protocol (ISATAP) tunnel.
+          Only applicable to SIT tunnels. When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>SerializeTunneledPackets=</varname></term>
         <listitem>
index 1b6a6d44dd8b77661fb0d1f4541c3d301f21393f..865b46f403e88ced9d9c19cfd89f5dd3c53a42e0 100644 (file)
       </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>[Neighbor] Section Options</title>
+      <para>A <literal>[Neighbor]</literal> section accepts the
+      following keys. The neighbor section adds a permanent, static
+      entry to the neighbor table (IPv6) or ARP table (IPv4) for
+      the given hardware address on the links matched for the network.
+      Specify several <literal>[Neighbor]</literal> sections to configure
+      several static neighbors.</para>
+
+      <variablelist class='network-directives'>
+        <varlistentry>
+          <term><varname>Address=</varname></term>
+          <listitem>
+            <para>The IP address of the neighbor.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>MACAddress=</varname></term>
+          <listitem>
+            <para>The hardware address of the neighbor.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
     <refsect1>
     <title>[IPv6AddressLabel] Section Options</title>
 
           </listitem>
         </varlistentry>
         <varlistentry>
-          <term><varname>Protocol=</varname></term>
+          <term><varname>IPProtocol=</varname></term>
           <listitem>
-            <para>Specifies the protocol to match in forwarding information base (FIB) rules. Accepted values are tcp, udp and sctp.
+            <para>Specifies the IP protocol to match in forwarding information base (FIB) rules. Takes IP protocol name such as <literal>tcp</literal>,
+            <literal>udp</literal> or <literal>sctp</literal>, or IP protocol number such as <literal>6</literal> for <literal>tcp</literal> or
+            <literal>17</literal> for <literal>udp</literal>.
             Defaults to unset.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>InvertRule=</varname></term>
+          <listitem>
+            <para>A boolean. Specifies wheather the rule to be inverted. Defaults to false.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
             </para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>MulticastToUnicast=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Multicast to unicast works on top of the multicast snooping feature of
+            the bridge. Which means unicast copies are only delivered to hosts which are interested in it.
+            When unset, the kernel's default will be used.
+            </para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>HairPin=</varname></term>
           <listitem>
index 4e282dad3d39e4b734ed7a6ca83743ca952325a9..aa7d9bcd59bff25e5d8d1c7e33b00383ddd12bfa 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>DisableControllers=</varname></term>
+
+        <listitem>
+          <para>Disables controllers from being enabled for a unit's children. If a controller listed is already in use
+          in its subtree, the controller will be removed from the subtree. This can be used to avoid child units being
+          able to implicitly or explicitly enable a controller. Defaults to not disabling any controllers.</para>
+
+          <para>It may not be possible to successfully disable a controller if the unit or any child of the unit in
+          question delegates controllers to its children, as any delegated subtree of the cgroup hierarchy is unmanaged
+          by systemd.</para>
+
+          <para>Multiple controllers may be specified, separated by spaces. You may also pass
+          <varname>DisableControllers=</varname> multiple times, in which case each new instance adds another controller
+          to disable. Passing <varname>DisableControllers=</varname> by itself with no controller name present resets
+          the disabled controller list.</para>
+
+          <para>Valid controllers are <option>cpu</option>, <option>cpuacct</option>, <option>io</option>,
+          <option>blkio</option>, <option>memory</option>, <option>devices</option>, and <option>pids</option>.</para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 998a047ec50a9512c2c9b1bd96a430e90aa01031..073c2b3a27c1412b3bc6b8d467322fe07c19b6bc 100644 (file)
@@ -6,7 +6,9 @@
   SPDX-License-Identifier: LGPL-2.1+
 -->
 
-<refentry id="systemd.swap">
+<refentry id="systemd.swap"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
+
   <refentryinfo>
     <title>systemd.swap</title>
     <productname>systemd</productname>
         successfully.</para>
         </listitem>
       </varlistentry>
+
+      <xi:include href="systemd.mount.xml" xpointer="device-timeout" />
+
+      <varlistentry>
+        <term><option>x-systemd.makefs</option></term>
+
+        <listitem><para>The swap structure will be initialized on the device. If the device is not
+        "empty", i.e. it contains any signature, the operation will be skipped. It is hence expected
+        that this option remains set even after the device has been initalized.</para>
+
+        <para>Note that this option can only be used in <filename>/etc/fstab</filename>, and will be
+        ignored when part of the <varname>Options=</varname> setting in a unit file.</para>
+
+        <para>See
+        <citerefentry><refentrytitle>systemd-mkswap@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        and the discussion of
+        <citerefentry project='man-pages'><refentrytitle>wipefs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        in <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        </para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 2c66db854b7a4724e2167458393528ea39faeeb0..26d215e3cc4e83616f46d519d67c06544ac3ca14 100644 (file)
       <varlistentry>
         <term><varname>JobTimeoutSec=</varname></term>
         <term><varname>JobRunningTimeoutSec=</varname></term>
-        <term><varname>JobTimeoutAction=</varname></term>
-        <term><varname>JobTimeoutRebootArgument=</varname></term>
 
         <listitem><para>When a job for this unit is queued, a time-out <varname>JobTimeoutSec=</varname> may be
         configured. Similarly, <varname>JobRunningTimeoutSec=</varname> starts counting when the queued job is actually
         no effect on the unit itself, only on the job that might be pending for it. Or in other words: unit-specific
         timeouts are useful to abort unit state changes, and revert them. The job timeout set with this option however
         is useful to abort only the job waiting for the unit state to change.</para>
+        </listitem>
+      </varlistentry>
 
-        <para><varname>JobTimeoutAction=</varname> optionally configures an additional action to take when the time-out
-        is hit. It takes the same values as <varname>StartLimitAction=</varname>. Defaults to <option>none</option>.
+      <varlistentry>
+        <term><varname>JobTimeoutAction=</varname></term>
+        <term><varname>JobTimeoutRebootArgument=</varname></term>
+
+        <listitem><para><varname>JobTimeoutAction=</varname> optionally configures an additional action to take when
+        the time-out is hit, see description of <varname>JobTimeoutSec=</varname> and
+        <varname>JobRunningTimeoutSec=</varname> above. It takes the same values as
+        <varname>StartLimitAction=</varname>. Defaults to <option>none</option>.
         <varname>JobTimeoutRebootArgument=</varname> configures an optional reboot string to pass to the
-        <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        system call.</para></listitem>
+        <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
         cgroup controller name (eg. <option>cpu</option>), verifying that it is
         available for use on the system. For example, a particular controller
         may not be available if it was disabled on the kernel command line with
-        <literal>cgroup_disable=</literal><replaceable>controller</replaceable>.
-        Multiple controllers may be passed with a space separating them; in
-        this case the condition will only pass if all listed controllers are
-        available for use. Controllers unknown to systemd are ignored. Valid
-        controllers are <option>cpu</option>, <option>cpuacct</option>,
-        <option>io</option>, <option>blkio</option>, <option>memory</option>,
+        <varname>cgroup_disable=controller</varname>. Multiple controllers may
+        be passed with a space separating them; in this case the condition will
+        only pass if all listed controllers are available for use. Controllers
+        unknown to systemd are ignored. Valid controllers are
+        <option>cpu</option>, <option>cpuacct</option>, <option>io</option>,
+        <option>blkio</option>, <option>memory</option>,
         <option>devices</option>, and <option>pids</option>.</para>
 
         <para>If multiple conditions are specified, the unit will be
index 37ae27b4a5c2d85d906d3ed96393ccb5aa0567fe..1f44c0fe70d327f4e84d902cff359e815a203eef 100644 (file)
@@ -227,6 +227,7 @@ conf.set_quoted('ROOTLIBEXECDIR',                             rootlibexecdir)
 conf.set_quoted('BOOTLIBDIR',                                 bootlibdir)
 conf.set_quoted('SYSTEMD_PULL_PATH',                          join_paths(rootlibexecdir, 'systemd-pull'))
 conf.set_quoted('SYSTEMD_IMPORT_PATH',                        join_paths(rootlibexecdir, 'systemd-import'))
+conf.set_quoted('SYSTEMD_IMPORT_FS_PATH',                     join_paths(rootlibexecdir, 'systemd-import-fs'))
 conf.set_quoted('SYSTEMD_EXPORT_PATH',                        join_paths(rootlibexecdir, 'systemd-export'))
 conf.set_quoted('VENDOR_KEYRING_PATH',                        join_paths(rootlibexecdir, 'import-pubring.gpg'))
 conf.set_quoted('USER_KEYRING_PATH',                          join_paths(pkgsysconfdir, 'import-pubring.gpg'))
@@ -396,7 +397,7 @@ if cc.compiles('''
            struct timespec now;
            return 0;
    }
-''', name : '-Werror=shadow with local shadowing')
+''', args: '-Werror=shadow', name : '-Werror=shadow with local shadowing')
         add_project_arguments('-Werror=shadow', language : 'c')
 endif
 
@@ -449,40 +450,89 @@ endforeach
 
 conf.set10('WANT_LINUX_STAT_H', want_linux_stat_h)
 
-foreach decl : [['IFLA_INET6_ADDR_GEN_MODE',                'linux/if_link.h'],
+foreach decl : [['ETHTOOL_LINK_MODE_10baseT_Half_BIT',      'linux/ethtool.h'],
+                ['ETHTOOL_LINK_MODE_25000baseCR_Full_BIT',  'linux/ethtool.h'],
+                ['ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT', 'linux/ethtool.h'],
+                ['ETHTOOL_LINK_MODE_1000baseX_Full_BIT',    'linux/ethtool.h'],
+                ['ETHTOOL_LINK_MODE_2500baseT_Full_BIT',    'linux/ethtool.h'],
+                ['ETHTOOL_LINK_MODE_FEC_NONE_BIT',          'linux/ethtool.h'],
+                ['FRA_TUN_ID',                              'linux/fib_rules.h'],
+                ['FRA_SUPPRESS_PREFIXLEN',                  'linux/fib_rules.h'],
+                ['FRA_PAD',                                 'linux/fib_rules.h'],
+                ['FRA_L3MDEV',                              'linux/fib_rules.h'],
+                ['FRA_UID_RANGE',                           'linux/fib_rules.h'],
+                ['FRA_DPORT_RANGE',                         'linux/fib_rules.h'],
+                ['FOU_ATTR_REMCSUM_NOPARTIAL',              'linux/fou.h'],
+                ['FOU_CMD_GET',                             'linux/fou.h'],
+                ['IFA_FLAGS',                               'linux/if_addr.h'],
+                ['IFLA_BRIDGE_VLAN_TUNNEL_INFO',            'linux/if_bridge.h'],
+                ['IFLA_INET6_ADDR_GEN_MODE',                'linux/if_link.h'],
                 ['IN6_ADDR_GEN_MODE_STABLE_PRIVACY',        'linux/if_link.h'],
-                ['IFLA_VRF_TABLE',                          'linux/if_link.h'],
-                ['IFLA_MACVLAN_FLAGS',                      'linux/if_link.h'],
+                ['IN6_ADDR_GEN_MODE_RANDOM',                'linux/if_link.h'],
+                ['IFLA_IPVLAN_MODE',                        'linux/if_link.h'],
+                ['IPVLAN_MODE_L3S',                         'linux/if_link.h'],
                 ['IFLA_IPVLAN_FLAGS',                       'linux/if_link.h'],
                 ['IFLA_PHYS_PORT_ID',                       'linux/if_link.h'],
+                ['IFLA_CARRIER_CHANGES',                    'linux/if_link.h'],
+                ['IFLA_PHYS_SWITCH_ID',                     'linux/if_link.h'],
+                ['IFLA_LINK_NETNSID',                       'linux/if_link.h'],
+                ['IFLA_PHYS_PORT_NAME',                     'linux/if_link.h'],
+                ['IFLA_PROTO_DOWN',                         'linux/if_link.h'],
+                ['IFLA_GSO_MAX_SIZE',                       'linux/if_link.h'],
+                ['IFLA_PAD',                                'linux/if_link.h'],
+                ['IFLA_XDP',                                'linux/if_link.h'],
+                ['IFLA_EVENT',                              'linux/if_link.h'],
+                ['IFLA_IF_NETNSID',                         'linux/if_link.h'],
+                ['IFLA_TARGET_NETNSID',                     'linux/if_link.h'],
+                ['IFLA_NEW_IFINDEX',                        'linux/if_link.h'],
+                ['IFLA_MAX_MTU',                            'linux/if_link.h'],
+                ['IFLA_BOND_ACTIVE_SLAVE',                  'linux/if_link.h'],
+                ['IFLA_BOND_AD_INFO',                       'linux/if_link.h'],
                 ['IFLA_BOND_AD_ACTOR_SYSTEM',               'linux/if_link.h'],
-                ['IFLA_VLAN_PROTOCOL',                      'linux/if_link.h'],
+                ['IFLA_BOND_TLB_DYNAMIC_LB',                'linux/if_link.h'],
+                ['IFLA_VXLAN_UDP_ZERO_CSUM6_RX',            'linux/if_link.h'],
                 ['IFLA_VXLAN_REMCSUM_NOPARTIAL',            'linux/if_link.h'],
+                ['IFLA_VXLAN_COLLECT_METADATA',             'linux/if_link.h'],
+                ['IFLA_VXLAN_LABEL',                        'linux/if_link.h'],
                 ['IFLA_VXLAN_GPE',                          'linux/if_link.h'],
+                ['IFLA_VXLAN_TTL_INHERIT',                  'linux/if_link.h'],
+                ['IFLA_GENEVE_TOS',                         'linux/if_link.h'],
+                ['IFLA_GENEVE_COLLECT_METADATA',            'linux/if_link.h'],
+                ['IFLA_GENEVE_REMOTE6',                     'linux/if_link.h'],
+                ['IFLA_GENEVE_UDP_ZERO_CSUM6_RX',           'linux/if_link.h'],
                 ['IFLA_GENEVE_LABEL',                       'linux/if_link.h'],
+                ['IFLA_GENEVE_TTL_INHERIT',                 'linux/if_link.h'],
+                ['IFLA_BR_MAX_AGE',                         'linux/if_link.h'],
+                ['IFLA_BR_PRIORITY',                        'linux/if_link.h'],
+                ['IFLA_BR_VLAN_PROTOCOL',                   'linux/if_link.h'],
+                ['IFLA_BR_VLAN_DEFAULT_PVID',               'linux/if_link.h'],
+                ['IFLA_BR_VLAN_STATS_ENABLED',              'linux/if_link.h'],
+                ['IFLA_BR_MCAST_STATS_ENABLED',             'linux/if_link.h'],
+                ['IFLA_BR_MCAST_MLD_VERSION',               'linux/if_link.h'],
+                ['IFLA_BR_VLAN_STATS_PER_PORT',             'linux/if_link.h'],
+                ['IFLA_BRPORT_LEARNING_SYNC',               'linux/if_link.h'],
+                ['IFLA_BRPORT_PROXYARP_WIFI',               'linux/if_link.h'],
+                ['IFLA_BRPORT_MULTICAST_ROUTER',            'linux/if_link.h'],
+                ['IFLA_BRPORT_PAD',                         'linux/if_link.h'],
+                ['IFLA_BRPORT_MCAST_FLOOD',                 'linux/if_link.h'],
+                ['IFLA_BRPORT_VLAN_TUNNEL',                 'linux/if_link.h'],
+                ['IFLA_BRPORT_BCAST_FLOOD',                 'linux/if_link.h'],
+                ['IFLA_BRPORT_NEIGH_SUPPRESS',              'linux/if_link.h'],
+                ['IFLA_BRPORT_ISOLATED',                    'linux/if_link.h'],
+                ['IFLA_BRPORT_BACKUP_PORT',                 'linux/if_link.h'],
+                ['IFLA_VRF_TABLE',                          'linux/if_link.h'],
                 # if_tunnel.h is buggy and cannot be included on its own
-                ['IFLA_VTI_REMOTE',                         'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_VTI_FWMARK',                         'linux/if_tunnel.h', '#include <net/if.h>'],
                 ['IFLA_IPTUN_ENCAP_DPORT',                  'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_IPTUN_COLLECT_METADATA',             'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_IPTUN_FWMARK',                       'linux/if_tunnel.h', '#include <net/if.h>'],
                 ['IFLA_GRE_ENCAP_DPORT',                    'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_GRE_COLLECT_METADATA',               'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_GRE_IGNORE_DF',                      'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_GRE_FWMARK',                         'linux/if_tunnel.h', '#include <net/if.h>'],
+                ['IFLA_GRE_ERSPAN_INDEX',                   'linux/if_tunnel.h', '#include <net/if.h>'],
                 ['IFLA_GRE_ERSPAN_HWID',                    'linux/if_tunnel.h', '#include <net/if.h>'],
-                ['IFLA_BRIDGE_VLAN_INFO',                   'linux/if_bridge.h'],
-                ['IFLA_BRPORT_PROXYARP',                    'linux/if_link.h'],
-                ['IFLA_BRPORT_LEARNING_SYNC',               'linux/if_link.h'],
-                ['IFLA_BR_VLAN_DEFAULT_PVID',               'linux/if_link.h'],
-                ['IPVLAN_F_PRIVATE',                        'linux/if_link.h'],
-                ['NDA_IFINDEX',                             'linux/neighbour.h'],
-                ['IFA_FLAGS',                               'linux/if_addr.h'],
-                ['FRA_DPORT_RANGE',                         'linux/fib_rules.h'],
                 ['LO_FLAGS_PARTSCAN',                       'linux/loop.h'],
-                ['VXCAN_INFO_PEER',                         'linux/can/vxcan.h'],
-                ['FOU_ATTR_REMCSUM_NOPARTIAL',              'linux/fou.h'],
-                ['FOU_CMD_GET',                             'linux/fou.h'],
-                ['ETHTOOL_LINK_MODE_10baseT_Half_BIT',      'linux/ethtool.h'],
-                ['ETHTOOL_LINK_MODE_25000baseCR_Full_BIT',  'linux/ethtool.h'],
-                ['ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT', 'linux/ethtool.h'],
-                ['ETHTOOL_LINK_MODE_1000baseX_Full_BIT',    'linux/ethtool.h'],
-                ['ETHTOOL_LINK_MODE_2500baseT_Full_BIT',    'linux/ethtool.h'],
-                ['ETHTOOL_LINK_MODE_FEC_NONE_BIT',          'linux/ethtool.h'],
                ]
         prefix = decl.length() > 2 ? decl[2] : ''
         have = cc.has_header_symbol(decl[1], decl[0], prefix : prefix)
@@ -613,10 +663,11 @@ if not cc.has_header('sys/capability.h')
         error('POSIX caps headers not found')
 endif
 foreach header : ['crypt.h',
-                  'linux/btrfs.h',
+                  'linux/btrfs_tree.h',
                   'linux/fou.h',
                   'linux/memfd.h',
                   'linux/vm_sockets.h',
+                  'linux/can/vxcan.h',
                   'sys/auxv.h',
                   'valgrind/memcheck.h',
                   'valgrind/valgrind.h',
@@ -2137,6 +2188,14 @@ if conf.get('ENABLE_IMPORTD') == 1
                                     install : true,
                                     install_dir : rootlibexecdir)
 
+        systemd_import_fs = executable('systemd-import-fs',
+                                    systemd_import_fs_sources,
+                                    include_directories : includes,
+                                    link_with : [libshared],
+                                    install_rpath : rootlibexecdir,
+                                    install : true,
+                                    install_dir : rootlibexecdir)
+
         systemd_export = executable('systemd-export',
                                     systemd_export_sources,
                                     include_directories : includes,
@@ -2148,7 +2207,8 @@ if conf.get('ENABLE_IMPORTD') == 1
                                     install_rpath : rootlibexecdir,
                                     install : true,
                                     install_dir : rootlibexecdir)
-        public_programs += [systemd_pull, systemd_import, systemd_export]
+
+        public_programs += [systemd_pull, systemd_import, systemd_import_fs, systemd_export]
 endif
 
 if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_LIBCURL') == 1
index cc5004a86f9e50f4667f5b48a29e62c26e561a2d..8306cdcfaf96e871d817dd072c927dbd0777e54c 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -7,525 +7,656 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd master\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2016-04-23 14:24+0200\n"
-"PO-Revision-Date: 2017-10-10 19:54+0200\n"
+"POT-Creation-Date: 2018-11-26 03:25+0000\n"
+"PO-Revision-Date: 2018-12-03 15:52+0100\n"
 "Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
+"Language-Team: Czech\n"
 "Language: cs\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? "
-"1 : 2);\n"
-"Language-Team: \n"
-"X-Generator: Poedit 2.0.3\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+"X-Generator: Poedit 2.2\n"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+#: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
 msgstr "Odeslat heslo zpět do systému"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
-msgid "Authentication is required to send the entered passphrase back to the system."
+#: src/core/org.freedesktop.systemd1.policy.in:23
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
 msgstr "Pro odeslání zadaného hesla do systému je vyžadováno ověření."
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+#: src/core/org.freedesktop.systemd1.policy.in:33
 msgid "Manage system services or other units"
 msgstr "Spravovat systémové služby nebo další jednotky"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+#: src/core/org.freedesktop.systemd1.policy.in:34
 msgid "Authentication is required to manage system services or other units."
-msgstr "Pro správu systémových služeb nebo dalších jednotek je vyžadováno ověření."
+msgstr ""
+"Pro správu systémových služeb nebo dalších jednotek je vyžadováno ověření."
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+#: src/core/org.freedesktop.systemd1.policy.in:43
 msgid "Manage system service or unit files"
 msgstr "Spravovat systémové služby nebo soubory jednotek"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+#: src/core/org.freedesktop.systemd1.policy.in:44
 msgid "Authentication is required to manage system service or unit files."
-msgstr "Pro správu systémových služeb nebo souborů jednotek je vyžadováno ověření."
+msgstr ""
+"Pro správu systémových služeb nebo souborů jednotek je vyžadováno ověření."
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+#: src/core/org.freedesktop.systemd1.policy.in:54
 msgid "Set or unset system and service manager environment variables"
 msgstr "Nastavit nebo rušit proměnné správce systému a služeb"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+#: src/core/org.freedesktop.systemd1.policy.in:55
 msgid ""
-"Authentication is required to set or unset system and service manager environment variables."
-msgstr "Pro nastavení nebo rušení proměnných správce systému a služeb je vyžadováno ověření."
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Pro nastavení nebo rušení proměnných správce systému a služeb je vyžadováno "
+"ověření."
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+#: src/core/org.freedesktop.systemd1.policy.in:64
 msgid "Reload the systemd state"
 msgstr "Znovu načíst stav systemd"
 
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+#: src/core/org.freedesktop.systemd1.policy.in:65
 msgid "Authentication is required to reload the systemd state."
 msgstr "Pro znovu načtení stavu systemd je vyžadováno ověření."
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+#: src/hostname/org.freedesktop.hostname1.policy:20
 msgid "Set host name"
 msgstr "Nastavit název stroje"
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+#: src/hostname/org.freedesktop.hostname1.policy:21
 msgid "Authentication is required to set the local host name."
 msgstr "Pro nastavení lokálního názvu stroje je vyžadováno ověření."
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+#: src/hostname/org.freedesktop.hostname1.policy:30
 msgid "Set static host name"
 msgstr "Nastavit statický název stroje"
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
+#: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, as well as the "
-"pretty host name."
+"Authentication is required to set the statically configured local host name, "
+"as well as the pretty host name."
 msgstr ""
-"Pro nastavení staticky konfigurovaného názvu lokálního stroje, stejně tak pro změnu "
-"uživatelsky přívětivého jména je vyžadováno ověření."
+"Pro nastavení staticky konfigurovaného názvu lokálního stroje, stejně tak "
+"pro změnu uživatelsky přívětivého jména je vyžadováno ověření."
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+#: src/hostname/org.freedesktop.hostname1.policy:41
 msgid "Set machine information"
 msgstr "Nastavit informace o stroji"
 
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+#: src/hostname/org.freedesktop.hostname1.policy:42
 msgid "Authentication is required to set local machine information."
 msgstr "Pro nastavení informací o stroji je vyžadováno ověření."
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:1
+#: src/hostname/org.freedesktop.hostname1.policy:51
+msgid "Get product UUID"
+msgstr "Získat UUID produktu"
+
+#: src/hostname/org.freedesktop.hostname1.policy:52
+msgid "Authentication is required to get product UUID."
+msgstr "Pro získání UUID produktu je vyžadováno ověření."
+
+#: src/import/org.freedesktop.import1.policy:22
 msgid "Import a VM or container image"
 msgstr "Importovat obraz virtuální stroje nebo kontejneru"
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:2
+#: src/import/org.freedesktop.import1.policy:23
 msgid "Authentication is required to import a VM or container image"
-msgstr "Pro import obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
+msgstr ""
+"Pro import obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:3
+#: src/import/org.freedesktop.import1.policy:32
 msgid "Export a VM or container image"
 msgstr "Exportovat obraz virtuálního stroje nebo kontejneru"
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:4
+#: src/import/org.freedesktop.import1.policy:33
 msgid "Authentication is required to export a VM or container image"
-msgstr "Pro export obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
+msgstr ""
+"Pro export obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:5
+#: src/import/org.freedesktop.import1.policy:42
 msgid "Download a VM or container image"
 msgstr "Stáhnout obraz virtuálního stroje nebo kontejneru"
 
-#: ../src/import/org.freedesktop.import1.policy.in.h:6
+#: src/import/org.freedesktop.import1.policy:43
 msgid "Authentication is required to download a VM or container image"
-msgstr "Pro stažení obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
+msgstr ""
+"Pro stažení obrazu virtuálního stroje nebo kontejneru je vyžadováno ověření"
 
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+#: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
 msgstr "Nastavit lokalizaci systému"
 
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+#: src/locale/org.freedesktop.locale1.policy:23
 msgid "Authentication is required to set the system locale."
 msgstr "Pro nastavení lokalizace systému je vyžadováno ověření."
 
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+#: src/locale/org.freedesktop.locale1.policy:33
 msgid "Set system keyboard settings"
 msgstr "Nastavit systémovou konfiguraci klávesnice"
 
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+#: src/locale/org.freedesktop.locale1.policy:34
 msgid "Authentication is required to set the system keyboard settings."
 msgstr "Pro nastavení systémové konfigurace klávesnice je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:1
+#: src/login/org.freedesktop.login1.policy:22
 msgid "Allow applications to inhibit system shutdown"
 msgstr "Povolit aplikacím zakázat vypnutí systému"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:2
-msgid "Authentication is required for an application to inhibit system shutdown."
+#: src/login/org.freedesktop.login1.policy:23
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
 msgstr "Pro povolení aplikacím zakázat vypnutí systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:3
+#: src/login/org.freedesktop.login1.policy:33
 msgid "Allow applications to delay system shutdown"
 msgstr "Povolit aplikacím odložit vypnutí systému"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:4
+#: src/login/org.freedesktop.login1.policy:34
 msgid "Authentication is required for an application to delay system shutdown."
 msgstr "Pro povolení aplikacím odložit vypnutí systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:5
+#: src/login/org.freedesktop.login1.policy:44
 msgid "Allow applications to inhibit system sleep"
 msgstr "Povolit aplikacím zakázat uspání systému"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:6
+#: src/login/org.freedesktop.login1.policy:45
 msgid "Authentication is required for an application to inhibit system sleep."
 msgstr "Pro povolení aplikacím zakázat uspání systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:7
+#: src/login/org.freedesktop.login1.policy:55
 msgid "Allow applications to delay system sleep"
 msgstr "Povolit aplikacím odložit uspání systému"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:8
+#: src/login/org.freedesktop.login1.policy:56
 msgid "Authentication is required for an application to delay system sleep."
 msgstr "Pro povolení aplikacím odložit uspání systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:9
+#: src/login/org.freedesktop.login1.policy:65
 msgid "Allow applications to inhibit automatic system suspend"
 msgstr "Povolit aplikacím zakázat automatické vypnutí systému"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:10
-msgid "Authentication is required for an application to inhibit automatic system suspend."
-msgstr "Pro povolení aplikacím zakázat automatické vypnutí systému je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:66
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr ""
+"Pro povolení aplikacím zakázat automatické vypnutí systému je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:11
+#: src/login/org.freedesktop.login1.policy:75
 msgid "Allow applications to inhibit system handling of the power key"
-msgstr "Povolit aplikacím zakázat chovaní systému na stisknutí vypínacího tlačítka"
+msgstr ""
+"Povolit aplikacím zakázat chovaní systému na stisknutí vypínacího tlačítka"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:12
+#: src/login/org.freedesktop.login1.policy:76
 msgid ""
-"Authentication is required for an application to inhibit system handling of the power key."
+"Authentication is required for an application to inhibit system handling of "
+"the power key."
 msgstr ""
-"Pro povolení aplikacím zakázat chovaní systému na stisknutí vypínacího tlačítka je "
-"vyžadováno ověření."
+"Pro povolení aplikacím zakázat chovaní systému na stisknutí vypínacího "
+"tlačítka je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:13
+#: src/login/org.freedesktop.login1.policy:86
 msgid "Allow applications to inhibit system handling of the suspend key"
-msgstr "Povolit aplikacím zakázat chovaní systému na stisknutí uspávacího tlačítka"
+msgstr ""
+"Povolit aplikacím zakázat chovaní systému na stisknutí uspávacího tlačítka"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:14
+#: src/login/org.freedesktop.login1.policy:87
 msgid ""
-"Authentication is required for an application to inhibit system handling of the suspend key."
+"Authentication is required for an application to inhibit system handling of "
+"the suspend key."
 msgstr ""
-"Pro povolení aplikacím zakázat chovaní systému na stisknutí uspávacího tlačítka je "
-"vyžadováno ověření."
+"Pro povolení aplikacím zakázat chovaní systému na stisknutí uspávacího "
+"tlačítka je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:15
+#: src/login/org.freedesktop.login1.policy:97
 msgid "Allow applications to inhibit system handling of the hibernate key"
-msgstr "Povolit aplikacím zakázat chovaní systému na stisknutí tlačítka hibernace"
+msgstr ""
+"Povolit aplikacím zakázat chovaní systému na stisknutí tlačítka hibernace"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:16
+#: src/login/org.freedesktop.login1.policy:98
 msgid ""
-"Authentication is required for an application to inhibit system handling of the hibernate "
-"key."
+"Authentication is required for an application to inhibit system handling of "
+"the hibernate key."
 msgstr ""
-"Pro povolení aplikacím zakázat chovaní systému na stisknutí tlačítka hibernace je vyžadováno "
-"ověření."
+"Pro povolení aplikacím zakázat chovaní systému na stisknutí tlačítka "
+"hibernace je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:17
+#: src/login/org.freedesktop.login1.policy:107
 msgid "Allow applications to inhibit system handling of the lid switch"
 msgstr "Povolit aplikacím zakázat chovaní systému na zavření víka"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:18
+#: src/login/org.freedesktop.login1.policy:108
 msgid ""
-"Authentication is required for an application to inhibit system handling of the lid switch."
-msgstr "Pro povolení aplikacím zakázat chovaní systému na zavření víka je vyžadováno ověření."
+"Authentication is required for an application to inhibit system handling of "
+"the lid switch."
+msgstr ""
+"Pro povolení aplikacím zakázat chovaní systému na zavření víka je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:19
+#: src/login/org.freedesktop.login1.policy:117
 msgid "Allow non-logged-in user to run programs"
 msgstr "Povolit nepřihlášenému uživateli spouštět programy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: src/login/org.freedesktop.login1.policy:118
 msgid "Explicit request is required to run programs as a non-logged-in user."
-msgstr "Ke spuštění programů jako nepřihlášený uživatel je třeba speciální požadavek."
+msgstr ""
+"Ke spuštění programů jako nepřihlášený uživatel je třeba speciální požadavek."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: src/login/org.freedesktop.login1.policy:127
 msgid "Allow non-logged-in users to run programs"
 msgstr "Povolit nepřihlášeným uživatelům spouštět programy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: src/login/org.freedesktop.login1.policy:128
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr "Ke spuštění programů jako nepřihlášený uživatel je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: src/login/org.freedesktop.login1.policy:137
 msgid "Allow attaching devices to seats"
 msgstr "Povolit připojování zařízení ke stanovištím"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: src/login/org.freedesktop.login1.policy:138
 msgid "Authentication is required for attaching a device to a seat."
 msgstr "Pro připojování zařízení ke stanovišti je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: src/login/org.freedesktop.login1.policy:148
 msgid "Flush device to seat attachments"
 msgstr "Odstranit přiřazení zařízení ke stanovištím"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
-msgid "Authentication is required for resetting how devices are attached to seats."
-msgstr "Pro reset způsobu jak jsou zařízení přiřazována ke stanovištím je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:149
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr ""
+"Pro reset způsobu jak jsou zařízení přiřazována ke stanovištím je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: src/login/org.freedesktop.login1.policy:158
 msgid "Power off the system"
 msgstr "Vypnout systém"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: src/login/org.freedesktop.login1.policy:159
 msgid "Authentication is required for powering off the system."
 msgstr "Pro vypnutí systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: src/login/org.freedesktop.login1.policy:169
 msgid "Power off the system while other users are logged in"
 msgstr "Vypnout systém, i když jsou přihlášeni další uživatelé"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
-msgid "Authentication is required for powering off the system while other users are logged in."
-msgstr "Pro vypnutí systému, když jsou přihlášeni další uživatelé je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:170
+msgid ""
+"Authentication is required for powering off the system while other users are "
+"logged in."
+msgstr ""
+"Pro vypnutí systému, když jsou přihlášeni další uživatelé je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: src/login/org.freedesktop.login1.policy:180
 msgid "Power off the system while an application asked to inhibit it"
 msgstr "Vypnout systém, i když aplikace požádala o zákaz vypnutí"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: src/login/org.freedesktop.login1.policy:181
 msgid ""
-"Authentication is required for powering off the system while an application asked to inhibit "
-"it."
-msgstr "Pro vypnutí systému, když aplikace požádala o zákaz vypnutí je vyžadováno ověření."
+"Authentication is required for powering off the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Pro vypnutí systému, když aplikace požádala o zákaz vypnutí je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: src/login/org.freedesktop.login1.policy:191
 msgid "Reboot the system"
 msgstr "Restartovat systém"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: src/login/org.freedesktop.login1.policy:192
 msgid "Authentication is required for rebooting the system."
 msgstr "Pro restartování systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: src/login/org.freedesktop.login1.policy:202
 msgid "Reboot the system while other users are logged in"
 msgstr "Restartovat systém, i když jsou přihlášeni další uživatelé"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
-msgid "Authentication is required for rebooting the system while other users are logged in."
-msgstr "Pro restartování systému, když jsou přihlášeni další uživatelé je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:203
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr ""
+"Pro restartování systému, když jsou přihlášeni další uživatelé je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: src/login/org.freedesktop.login1.policy:213
 msgid "Reboot the system while an application asked to inhibit it"
 msgstr "Restartovat systém, i když aplikace požádala o zákaz restartu"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: src/login/org.freedesktop.login1.policy:214
 msgid ""
-"Authentication is required for rebooting the system while an application asked to inhibit it."
+"Authentication is required for rebooting the system while an application "
+"asked to inhibit it."
 msgstr ""
-"Pro restartování systému, když aplikace požádala o zákaz restartu je vyžadováno ověření."
+"Pro restartování systému, když aplikace požádala o zákaz restartu je "
+"vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: src/login/org.freedesktop.login1.policy:224
 msgid "Halt the system"
 msgstr "Zastavit systém"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: src/login/org.freedesktop.login1.policy:225
 msgid "Authentication is required for halting the system."
 msgstr "Pro zastavení systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: src/login/org.freedesktop.login1.policy:235
 msgid "Halt the system while other users are logged in"
 msgstr "Zastavit systém, i když jsou přihlášeni další uživatelé"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
-msgid "Authentication is required for halting the system while other users are logged in."
-msgstr "Pro zastavení systému, když jsou přihlášeni další uživatelé je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:236
+msgid ""
+"Authentication is required for halting the system while other users are "
+"logged in."
+msgstr ""
+"Pro zastavení systému, když jsou přihlášeni další uživatelé je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: src/login/org.freedesktop.login1.policy:246
 msgid "Halt the system while an application asked to inhibit it"
 msgstr "Zastavit systém, i když aplikace požádala o zákaz zastavení"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: src/login/org.freedesktop.login1.policy:247
 msgid ""
-"Authentication is required for halting the system while an application asked to inhibit it."
-msgstr "Pro zastavení systému, když aplikace požádala o zákaz zastavení je vyžadováno ověření."
+"Authentication is required for halting the system while an application asked "
+"to inhibit it."
+msgstr ""
+"Pro zastavení systému, když aplikace požádala o zákaz zastavení je "
+"vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: src/login/org.freedesktop.login1.policy:257
 msgid "Suspend the system"
 msgstr "Uspat systém"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: src/login/org.freedesktop.login1.policy:258
 msgid "Authentication is required for suspending the system."
 msgstr "Pro uspání systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: src/login/org.freedesktop.login1.policy:267
 msgid "Suspend the system while other users are logged in"
 msgstr "Uspat systém, i když jsou přihlášeni další uživatelé"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
-msgid "Authentication is required for suspending the system while other users are logged in."
-msgstr "Pro uspání systému, když jsou přihlášeni další uživatelé je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:268
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr ""
+"Pro uspání systému, když jsou přihlášeni další uživatelé je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: src/login/org.freedesktop.login1.policy:278
 msgid "Suspend the system while an application asked to inhibit it"
 msgstr "Uspat systém, i když aplikace požádala o zákaz uspání"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: src/login/org.freedesktop.login1.policy:279
 msgid ""
-"Authentication is required for suspending the system while an application asked to inhibit "
-"it."
-msgstr "Pro uspání systému, když aplikace požádala o zákaz uspání je vyžadováno ověření."
+"Authentication is required for suspending the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Pro uspání systému, když aplikace požádala o zákaz uspání je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: src/login/org.freedesktop.login1.policy:289
 msgid "Hibernate the system"
 msgstr "Hibernovat systém"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: src/login/org.freedesktop.login1.policy:290
 msgid "Authentication is required for hibernating the system."
 msgstr "Pro hibernaci systému je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: src/login/org.freedesktop.login1.policy:299
 msgid "Hibernate the system while other users are logged in"
 msgstr "Hibernovat systém, i když jsou přihlášeni další uživatelé"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
-msgid "Authentication is required for hibernating the system while other users are logged in."
-msgstr "Pro hibernaci systému, když jsou přihlášeni další uživatelé je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:300
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr ""
+"Pro hibernaci systému, když jsou přihlášeni další uživatelé je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while an application asked to inhibit it"
 msgstr "Hibernovat systém, i když aplikace požádala o zákaz hibernace"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: src/login/org.freedesktop.login1.policy:311
 msgid ""
-"Authentication is required for hibernating the system while an application asked to inhibit "
-"it."
-msgstr "Pro hibernaci systému, když aplikace požádala o zákaz hibernace je vyžadováno ověření."
+"Authentication is required for hibernating the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Pro hibernaci systému, když aplikace požádala o zákaz hibernace je "
+"vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:57
+#: src/login/org.freedesktop.login1.policy:321
 msgid "Manage active sessions, users and seats"
 msgstr "Spravovat aktivní sezení, uživatele a stanoviště"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:58
-msgid "Authentication is required for managing active sessions, users and seats."
-msgstr "Pro správu aktivních sezení, uživatelů a stanovišť je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:322
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Pro správu aktivních sezení, uživatelů a stanovišť je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:59
+#: src/login/org.freedesktop.login1.policy:331
 msgid "Lock or unlock active sessions"
 msgstr "Zamknout nebo odemknout aktivní sezení"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:60
+#: src/login/org.freedesktop.login1.policy:332
 msgid "Authentication is required to lock or unlock active sessions."
 msgstr "Pro zamčení nebo odemčení aktivních sezení je vyžadováno ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:61
+#: src/login/org.freedesktop.login1.policy:341
 msgid "Allow indication to the firmware to boot to setup interface"
 msgstr "Povolit indikaci firmwaru bootovat instalační prostředí"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:62
-msgid "Authentication is required to indicate to the firmware to boot to setup interface."
-msgstr "K povolení indikace firmwaru bootovat instalační prostředí je vyžadováno ověření."
+#: src/login/org.freedesktop.login1.policy:342
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr ""
+"K povolení indikace firmwaru bootovat instalační prostředí je vyžadováno "
+"ověření."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:63
+#: src/login/org.freedesktop.login1.policy:352
 msgid "Set a wall message"
 msgstr "Nastavit zprávu všem uživatelům"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:64
+#: src/login/org.freedesktop.login1.policy:353
 msgid "Authentication is required to set a wall message"
 msgstr "K nastavení zprávy všem uživatelům je vyžadováno ověření"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+#: src/machine/org.freedesktop.machine1.policy:22
 msgid "Log into a local container"
 msgstr "Přihlásit se do lokálního kontejneru"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+#: src/machine/org.freedesktop.machine1.policy:23
 msgid "Authentication is required to log into a local container."
 msgstr "Pro přihlášení do lokálního kontejneru je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+#: src/machine/org.freedesktop.machine1.policy:32
 msgid "Log into the local host"
 msgstr "Přihlásit se na lokální stroj"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+#: src/machine/org.freedesktop.machine1.policy:33
 msgid "Authentication is required to log into the local host."
 msgstr "Pro přihlášení k lokálnímu stroji je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+#: src/machine/org.freedesktop.machine1.policy:42
 msgid "Acquire a shell in a local container"
 msgstr "Získat shell v lokálním kontejneru"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+#: src/machine/org.freedesktop.machine1.policy:43
 msgid "Authentication is required to acquire a shell in a local container."
 msgstr "Pro získání shellu v lokálním kontejneru je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+#: src/machine/org.freedesktop.machine1.policy:53
 msgid "Acquire a shell on the local host"
 msgstr "Získat shell na lokálním stroji"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+#: src/machine/org.freedesktop.machine1.policy:54
 msgid "Authentication is required to acquire a shell on the local host."
 msgstr "Pro získání shellu na lokálním stroji je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+#: src/machine/org.freedesktop.machine1.policy:64
 msgid "Acquire a pseudo TTY in a local container"
 msgstr "Získat pseudo TTY v lokálním kontejneru"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
-msgid "Authentication is required to acquire a pseudo TTY in a local container."
+#: src/machine/org.freedesktop.machine1.policy:65
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
 msgstr "Pro získání pseudo TTY v lokálním kontejneru je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+#: src/machine/org.freedesktop.machine1.policy:74
 msgid "Acquire a pseudo TTY on the local host"
 msgstr "Získat pseudo TTY na lokálním stroji"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+#: src/machine/org.freedesktop.machine1.policy:75
 msgid "Authentication is required to acquire a pseudo TTY on the local host."
 msgstr "Pro získání pseudo TTY na lokálním stroji je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+#: src/machine/org.freedesktop.machine1.policy:84
 msgid "Manage local virtual machines and containers"
 msgstr "Spravovat lokální virtuální stroje a kontejnery"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
-msgid "Authentication is required to manage local virtual machines and containers."
-msgstr "Pro správu lokálních virtuálních strojů a kontejnerů je vyžadováno ověření."
+#: src/machine/org.freedesktop.machine1.policy:85
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Pro správu lokálních virtuálních strojů a kontejnerů je vyžadováno ověření."
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
+#: src/machine/org.freedesktop.machine1.policy:95
 msgid "Manage local virtual machine and container images"
 msgstr "Spravovat lokální obrazy virtuálních strojů a kontejnerů"
 
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
-msgid "Authentication is required to manage local virtual machine and container images."
-msgstr "Pro správu obrazů lokálních virtuálních strojů a kontejnerů je vyžadováno ověření."
+#: src/machine/org.freedesktop.machine1.policy:96
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Pro správu obrazů lokálních virtuálních strojů a kontejnerů je vyžadováno "
+"ověření."
+
+#: src/portable/org.freedesktop.portable1.policy:13
+msgid "Inspect a portable service image"
+msgstr "Prohlédnout obraz přenosné služby"
+
+#: src/portable/org.freedesktop.portable1.policy:14
+msgid "Authentication is required to inspect a portable service image."
+msgstr "Pro prohlížení obrazu přenosné služby je vyžadováno ověření."
+
+#: src/portable/org.freedesktop.portable1.policy:23
+msgid "Attach or detach a portable service image"
+msgstr "Připojit nebo odpojit obraz přenosné služby"
+
+#: src/portable/org.freedesktop.portable1.policy:24
+msgid ""
+"Authentication is required to attach or detach a portable service image."
+msgstr ""
+"Pro připojení nebo odpojení obrazu přenosné služby je vyžadováno ověření."
+
+#: src/portable/org.freedesktop.portable1.policy:34
+msgid "Delete or modify portable service image"
+msgstr "Odstranit nebo upravit obraz přenosné služby"
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+#: src/portable/org.freedesktop.portable1.policy:35
+msgid ""
+"Authentication is required to delete or modify a portable service image."
+msgstr ""
+"Pro odstranění nebo úpravu obrazu přenosné služby je vyžadováno ověření."
+
+#: src/resolve/org.freedesktop.resolve1.policy:22
+msgid "Register a DNS-SD service"
+msgstr "Registrovat službu DNS-SD"
+
+#: src/resolve/org.freedesktop.resolve1.policy:23
+msgid "Authentication is required to register a DNS-SD service"
+msgstr "Pro registraci služby DNS-SD je vyžadováno ověření"
+
+#: src/resolve/org.freedesktop.resolve1.policy:33
+msgid "Unregister a DNS-SD service"
+msgstr "Zrušit registraci služby DNS-SD"
+
+#: src/resolve/org.freedesktop.resolve1.policy:34
+msgid "Authentication is required to unregister a DNS-SD service"
+msgstr "Pro zrušení registrace služby DNS-SD je vyžadováno ověření"
+
+#: src/timedate/org.freedesktop.timedate1.policy:22
 msgid "Set system time"
 msgstr "Nastavit systémový čas"
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+#: src/timedate/org.freedesktop.timedate1.policy:23
 msgid "Authentication is required to set the system time."
 msgstr "Pro nastavení systémového času je vyžadováno ověření."
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+#: src/timedate/org.freedesktop.timedate1.policy:33
 msgid "Set system timezone"
 msgstr "Nastavit systémovou časovou zónu"
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+#: src/timedate/org.freedesktop.timedate1.policy:34
 msgid "Authentication is required to set the system timezone."
 msgstr "Pro nastavení systémové časové zóny je vyžadováno ověření."
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+#: src/timedate/org.freedesktop.timedate1.policy:43
 msgid "Set RTC to local timezone or UTC"
 msgstr "Nastavit RTC na lokální časovou zónu nebo UTC"
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6
-msgid "Authentication is required to control whether the RTC stores the local or UTC time."
+#: src/timedate/org.freedesktop.timedate1.policy:44
+msgid ""
+"Authentication is required to control whether the RTC stores the local or "
+"UTC time."
 msgstr ""
-"Pro kontrolu jestli RTC ukládá lokální časovou zónu nebo UTC čas je vyžadováno ověření."
+"Pro kontrolu jestli RTC ukládá lokální časovou zónu nebo UTC čas je "
+"vyžadováno ověření."
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+#: src/timedate/org.freedesktop.timedate1.policy:53
 msgid "Turn network time synchronization on or off"
 msgstr "Zapnout nebo vypnout synchronizaci s časem ze sítě"
 
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+#: src/timedate/org.freedesktop.timedate1.policy:54
 msgid ""
-"Authentication is required to control whether network time synchronization shall be enabled."
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
 msgstr "Pro kontrolu synchronizace času ze sítě je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:458
+#: src/core/dbus-unit.c:326
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Pro spuštění „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:459
+#: src/core/dbus-unit.c:327
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Pro vypnutí „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:460
+#: src/core/dbus-unit.c:328
 msgid "Authentication is required to reload '$(unit)'."
 msgstr "Pro znovu načtení „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:461 ../src/core/dbus-unit.c:462
+#: src/core/dbus-unit.c:329 src/core/dbus-unit.c:330
 msgid "Authentication is required to restart '$(unit)'."
 msgstr "Pro restart „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:569
-msgid "Authentication is required to kill '$(unit)'."
-msgstr "Pro ukončení „$(unit)” je vyžadováno ověření."
+#: src/core/dbus-unit.c:437
+msgid ""
+"Authentication is required to send a UNIX signal to the processes of "
+"'$(unit)'."
+msgstr "Pro odeslání UNIX signálu procesům „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:600
+#: src/core/dbus-unit.c:468
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr "Pro resetování chybného stavu „$(unit)” je vyžadováno ověření."
 
-#: ../src/core/dbus-unit.c:633
+#: src/core/dbus-unit.c:501
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr "Pro nastavení vlastností na „$(unit)” je vyžadováno ověření."
+
+#~ msgid "Authentication is required to kill '$(unit)'."
+#~ msgstr "Pro ukončení „$(unit)” je vyžadováno ověření."
index 343fc06f852abbebb92028147e1767680fb20f70..a1458e91887f7efbf4ad1bf58a66e8177af34be3 100644 (file)
@@ -8,4 +8,4 @@ ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_
 ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
 
 # watch metadata changes, caused by tools closing the device node which was opened for writing
-ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*", OPTIONS+="watch"
+ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*|dasd*", OPTIONS+="watch"
index a8bc752f1e98a8abc6969e4df9cd814e0be5a8a9..6c8c0c14c66b7b2bef6dbeb2e89be5799e7bd032 100644 (file)
@@ -30,8 +30,13 @@ __get_machines() {
         machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; };
 }
 
+__get_services() {
+        systemctl list-units --no-legend --no-pager -t service --all $1 | \
+                { while read -r a b c; do [[ $b == "loaded" ]]; echo " $a"; done }
+}
+
 _systemd_analyze() {
-        local i verb comps
+        local i verb comps mode
         local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
 
         local -A OPTS=(
@@ -50,6 +55,7 @@ _systemd_analyze() {
                 [SECCOMP_FILTER]='syscall-filter'
                 [SERVICE_WATCHDOGS]='service-watchdogs'
                 [CAT_CONFIG]='cat-config'
+                [SECURITY]='security'
         )
 
         local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@@ -148,6 +154,18 @@ _systemd_analyze() {
                         comps="$CONFIGS $( compgen -A file -- "$cur" )"
                         compopt -o filenames
                 fi
+
+        elif __contains_word "$verb" ${VERBS[SECURITY]}; then
+                if [[ $cur = -* ]]; then
+                        comps='--help --version --no-pager --system --user -H --host -M --machine'
+                else
+                        if __contains_word "--user" ${COMP_WORDS[*]}; then
+                                mode=--user
+                        else
+                                mode=--system
+                        fi
+                        comps=$( __get_services $mode )
+                fi
         fi
 
         COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
index 912772d590c974547dc72fd3e3bad7997b0eee8a..9a83bc7f24378e9f0484a2e1007c3892af71c76a 100644 (file)
@@ -249,7 +249,7 @@ static int fork_and_exec_process(const char* child, char** argv, char **env, int
         if (!joined)
                 return log_oom();
 
-        r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &child_pid);
+        r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &child_pid);
         if (r < 0)
                 return r;
         if (r == 0) {
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c
new file mode 100644 (file)
index 0000000..cdbe2b3
--- /dev/null
@@ -0,0 +1,2086 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sched.h>
+#include <sys/utsname.h>
+
+#include "analyze-security.h"
+#include "bus-error.h"
+#include "bus-unit-util.h"
+#include "bus-util.h"
+#include "env-util.h"
+#include "format-table.h"
+#include "in-addr-util.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#if HAVE_SECCOMP
+#  include "seccomp-util.h"
+#endif
+#include "set.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-def.h"
+#include "unit-name.h"
+
+struct security_info {
+        char *id;
+        char *type;
+        char *load_state;
+        char *fragment_path;
+        bool default_dependencies;
+
+        uint64_t ambient_capabilities;
+        uint64_t capability_bounding_set;
+
+        char *user;
+        char **supplementary_groups;
+        bool dynamic_user;
+
+        bool ip_address_deny_all;
+        bool ip_address_allow_localhost;
+        bool ip_address_allow_other;
+
+        char *keyring_mode;
+        bool lock_personality;
+        bool memory_deny_write_execute;
+        bool no_new_privileges;
+        char *notify_access;
+
+        bool private_devices;
+        bool private_mounts;
+        bool private_network;
+        bool private_tmp;
+        bool private_users;
+
+        bool protect_control_groups;
+        bool protect_kernel_modules;
+        bool protect_kernel_tunables;
+
+        char *protect_home;
+        char *protect_system;
+
+        bool remove_ipc;
+
+        bool restrict_address_family_inet;
+        bool restrict_address_family_unix;
+        bool restrict_address_family_netlink;
+        bool restrict_address_family_packet;
+        bool restrict_address_family_other;
+
+        uint64_t restrict_namespaces;
+        bool restrict_realtime;
+
+        char *root_directory;
+        char *root_image;
+
+        bool delegate;
+        char *device_policy;
+        bool device_allow_non_empty;
+
+        char **system_call_architectures;
+
+        bool system_call_filter_whitelist;
+        Set *system_call_filter;
+
+        uint32_t _umask;
+};
+
+struct security_assessor {
+        const char *id;
+        const char *description_good;
+        const char *description_bad;
+        const char *description_na;
+        const char *url;
+        uint64_t weight;
+        uint64_t range;
+        int (*assess)(const struct security_assessor *a, const struct security_info *info, const void *data, uint64_t *ret_badness, char **ret_description);
+        size_t offset;
+        uint64_t parameter;
+        bool default_dependencies_only;
+};
+
+static void security_info_free(struct security_info *i) {
+        if (!i)
+                return;
+
+        free(i->id);
+        free(i->type);
+        free(i->load_state);
+        free(i->fragment_path);
+
+        free(i->user);
+
+        free(i->protect_home);
+        free(i->protect_system);
+
+        free(i->root_directory);
+        free(i->root_image);
+
+        free(i->keyring_mode);
+        free(i->notify_access);
+
+        free(i->device_policy);
+
+        strv_free(i->supplementary_groups);
+        strv_free(i->system_call_architectures);
+
+        set_free_free(i->system_call_filter);
+}
+
+static bool security_info_runs_privileged(const struct security_info *i)  {
+        assert(i);
+
+        if (STRPTR_IN_SET(i->user, "0", "root"))
+                return true;
+
+        if (i->dynamic_user)
+                return false;
+
+        return isempty(i->user);
+}
+
+static int assess_bool(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        const bool *b = data;
+
+        assert(b);
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = a->parameter ? *b : !*b;
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_user(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        _cleanup_free_ char *d = NULL;
+        uint64_t b;
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (streq_ptr(info->user, NOBODY_USER_NAME)) {
+                d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
+                b = 9;
+        } else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
+                d = strdup("Service runs under a transient non-root user identity");
+                b = 0;
+        } else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
+                d = strdup("Service runs under a static non-root user identity");
+                b = 0;
+        } else {
+                *ret_badness = 10;
+                *ret_description = NULL;
+                return 0;
+        }
+
+        if (!d)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = TAKE_PTR(d);
+
+        return 0;
+}
+
+static int assess_protect_home(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        const char *description;
+        uint64_t badness;
+        char *copy;
+        int r;
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        badness = 10;
+        description = "Service has full access to home directories";
+
+        r = parse_boolean(info->protect_home);
+        if (r < 0) {
+                if (streq_ptr(info->protect_home, "read-only")) {
+                        badness = 5;
+                        description = "Service has read-only access to home directories";
+                } else if (streq_ptr(info->protect_home, "tmpfs")) {
+                        badness = 1;
+                        description = "Service has access to fake empty home directories";
+                }
+        } else if (r > 0) {
+                badness = 0;
+                description = "Service has no access to home directories";
+        }
+
+        copy = strdup(description);
+        if (!copy)
+                return log_oom();
+
+        *ret_badness = badness;
+        *ret_description = copy;
+
+        return 0;
+}
+
+static int assess_protect_system(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        const char *description;
+        uint64_t badness;
+        char *copy;
+        int r;
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        badness = 10;
+        description = "Service has full access to the OS file hierarchy";
+
+        r = parse_boolean(info->protect_system);
+        if (r < 0) {
+                if (streq_ptr(info->protect_system, "full")) {
+                        badness = 3;
+                        description = "Service has very limited write access to the OS file hierarchy";
+                } else if (streq_ptr(info->protect_system, "strict")) {
+                        badness = 0;
+                        description = "Service has strict read-only access to the OS file hierarchy";
+                }
+        } else if (r > 0) {
+                badness = 5;
+                description = "Service has limited write access to the OS file hierarchy";
+        }
+
+        copy = strdup(description);
+        if (!copy)
+                return log_oom();
+
+        *ret_badness = badness;
+        *ret_description = copy;
+
+        return 0;
+}
+
+static int assess_root_directory(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness =
+                (isempty(info->root_directory) ||
+                 path_equal(info->root_directory, "/")) &&
+                (isempty(info->root_image) ||
+                 path_equal(info->root_image, "/"));
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_capability_bounding_set(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = !!(info->capability_bounding_set & a->parameter);
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_umask(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        char *copy = NULL;
+        const char *d;
+        uint64_t b;
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (!FLAGS_SET(info->_umask, 0002)) {
+                d = "Files created by service are world-writable by default";
+                b = 10;
+        } else if (!FLAGS_SET(info->_umask, 0004)) {
+                d = "Files created by service are world-readable by default";
+                b = 5;
+        } else if (!FLAGS_SET(info->_umask, 0020)) {
+                d = "Files created by service are group-writable by default";
+                b = 2;
+        } else if (!FLAGS_SET(info->_umask, 0040)) {
+                d = "Files created by service are group-readable by default";
+                b = 1;
+        } else {
+                d = "Files created by service are accessible only by service's own user by default";
+                b = 0;
+        }
+
+        copy = strdup(d);
+        if (!copy)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = copy;
+
+        return 0;
+}
+
+static int assess_keyring_mode(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = !streq_ptr(info->keyring_mode, "private");
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_notify_access(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = streq_ptr(info->notify_access, "all");
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_remove_ipc(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (security_info_runs_privileged(info))
+                *ret_badness = UINT64_MAX;
+        else
+                *ret_badness = !info->remove_ipc;
+
+        *ret_description = NULL;
+        return 0;
+}
+
+static int assess_supplementary_groups(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (security_info_runs_privileged(info))
+                *ret_badness = UINT64_MAX;
+        else
+                *ret_badness = !strv_isempty(info->supplementary_groups);
+
+        *ret_description = NULL;
+        return 0;
+}
+
+static int assess_restrict_namespaces(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = !!(info->restrict_namespaces & a->parameter);
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static int assess_system_call_architectures(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        char *d;
+        uint64_t b;
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (strv_isempty(info->system_call_architectures)) {
+                b = 10;
+                d = strdup("Service may execute system calls with all ABIs");
+        } else if (strv_equal(info->system_call_architectures, STRV_MAKE("native"))) {
+                b = 0;
+                d = strdup("Service may execute system calls only with native ABI");
+        } else {
+                b = 8;
+                d = strdup("Service may execute system calls with multiple ABIs");
+        }
+
+        if (!d)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = d;
+
+        return 0;
+}
+
+#if HAVE_SECCOMP
+
+static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterSet *f) {
+        const char *syscall;
+
+        NULSTR_FOREACH(syscall, f->value) {
+                bool b;
+
+                if (syscall[0] == '@') {
+                        const SyscallFilterSet *g;
+                        assert_se(g = syscall_filter_set_find(syscall));
+                        b = syscall_names_in_filter(s, whitelist, g);
+                } else {
+                        int id;
+
+                        /* Let's see if the system call actually exists on this platform, before complaining */
+                        id = seccomp_syscall_resolve_name(syscall);
+                        if (id < 0)
+                                continue;
+
+                        b = set_contains(s, syscall);
+                }
+
+                if (whitelist == b) {
+                        log_debug("Offending syscall filter item: %s", syscall);
+                        return true; /* bad! */
+                }
+        }
+
+        return false;
+}
+
+static int assess_system_call_filter(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        const SyscallFilterSet *f;
+        char *d = NULL;
+        uint64_t b;
+
+        assert(a);
+        assert(info);
+        assert(ret_badness);
+        assert(ret_description);
+
+        assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
+        f = syscall_filter_sets + a->parameter;
+
+        if (!info->system_call_filter_whitelist && set_isempty(info->system_call_filter)) {
+                d = strdup("Service does not filter system calls");
+                b = 10;
+        } else {
+                bool bad;
+
+                log_debug("Analyzing system call filter, checking against: %s", f->name);
+                bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_whitelist, f);
+                log_debug("Result: %s", bad ? "bad" : "good");
+
+                if (info->system_call_filter_whitelist) {
+                        if (bad) {
+                                (void) asprintf(&d, "System call whitelist defined for service, and %s is included", f->name);
+                                b = 9;
+                        } else {
+                                (void) asprintf(&d, "System call whitelist defined for service, and %s is not included", f->name);
+                                b = 0;
+                        }
+                } else {
+                        if (bad) {
+                                (void) asprintf(&d, "System call blacklist defined for service, and %s is not included", f->name);
+                                b = 10;
+                        } else {
+                                (void) asprintf(&d, "System call blacklist defined for service, and %s is included", f->name);
+                                b = 5;
+                        }
+                }
+        }
+
+        if (!d)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = d;
+
+        return 0;
+}
+
+#endif
+
+static int assess_ip_address_allow(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        char *d = NULL;
+        uint64_t b;
+
+        assert(info);
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (!info->ip_address_deny_all) {
+                d = strdup("Service does not define an IP address whitelist");
+                b = 10;
+        } else if (info->ip_address_allow_other) {
+                d = strdup("Service defines IP address whitelist with non-localhost entries");
+                b = 5;
+        } else if (info->ip_address_allow_localhost) {
+                d = strdup("Service defines IP address whitelits with only localhost entries");
+                b = 2;
+        } else {
+                d = strdup("Service blocks all IP address ranges");
+                b = 0;
+        }
+
+        if (!d)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = d;
+
+        return 0;
+}
+
+static int assess_device_allow(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        char *d = NULL;
+        uint64_t b;
+
+        assert(info);
+        assert(ret_badness);
+        assert(ret_description);
+
+        if (STRPTR_IN_SET(info->device_policy, "strict", "closed")) {
+
+                if (info->device_allow_non_empty) {
+                        d = strdup("Service has a device ACL with some special devices");
+                        b = 5;
+                } else {
+                        d = strdup("Service has a minimal device ACL");
+                        b = 0;
+                }
+        } else {
+                d = strdup("Service has no device ACL");
+                b = 10;
+        }
+
+        if (!d)
+                return log_oom();
+
+        *ret_badness = b;
+        *ret_description = d;
+
+        return 0;
+}
+
+static int assess_ambient_capabilities(
+                const struct security_assessor *a,
+                const struct security_info *info,
+                const void *data,
+                uint64_t *ret_badness,
+                char **ret_description) {
+
+        assert(ret_badness);
+        assert(ret_description);
+
+        *ret_badness = info->ambient_capabilities != 0;
+        *ret_description = NULL;
+
+        return 0;
+}
+
+static const struct security_assessor security_assessor_table[] = {
+        {
+                .id = "User=/DynamicUser=",
+                .description_bad = "Service runs as root user",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#User=",
+                .weight = 2000,
+                .range = 10,
+                .assess = assess_user,
+        },
+        {
+                .id = "SupplementaryGroups=",
+                .description_good = "Service has no supplementary groups",
+                .description_bad = "Service runs with supplementary groups",
+                .description_na = "Service runs as root, option does not matter",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SupplementaryGroups=",
+                .weight = 200,
+                .range = 1,
+                .assess = assess_supplementary_groups,
+        },
+        {
+                .id = "PrivateDevices=",
+                .description_good = "Service has no access to hardware devices",
+                .description_bad = "Service potentially has access to hardware devices",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateDevices=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, private_devices),
+        },
+        {
+                .id = "PrivateMounts=",
+                .description_good = "Service cannot install system mounts",
+                .description_bad = "Service may install system mounts",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateMounts=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, private_mounts),
+        },
+        {
+                .id = "PrivateNetwork=",
+                .description_good = "Service has no access to the host's network",
+                .description_bad = "Service has access to the host's network",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateNetwork=",
+                .weight = 2500,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, private_network),
+        },
+        {
+                .id = "PrivateTmp=",
+                .description_good = "Service has no access to other software's temporary files",
+                .description_bad = "Service has access to other software's temporary files",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateTmp=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, private_tmp),
+                .default_dependencies_only = true,
+        },
+        {
+                .id = "PrivateUsers=",
+                .description_good = "Service does not have access to other users",
+                .description_bad = "Service has access to other users",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateUsers=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, private_users),
+        },
+        {
+                .id = "ProtectControlGroups=",
+                .description_good = "Service cannot modify the control group file system",
+                .description_bad = "Service may modify to the control group file system",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectControlGroups=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, protect_control_groups),
+        },
+        {
+                .id = "ProtectKernelModules=",
+                .description_good = "Service cannot load or read kernel modules",
+                .description_bad = "Service may load or read kernel modules",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelModules=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, protect_kernel_modules),
+        },
+        {
+                .id = "ProtectKernelTunables=",
+                .description_good = "Service cannot alter kernel tunables (/proc/sys, …)",
+                .description_bad = "Service may alter kernel tunables",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelTunables=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, protect_kernel_tunables),
+        },
+        {
+                .id = "ProtectHome=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_protect_home,
+                .default_dependencies_only = true,
+        },
+        {
+                .id = "ProtectSystem=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_protect_system,
+                .default_dependencies_only = true,
+        },
+        {
+                .id = "RootDirectory=/RootImage=",
+                .description_good = "Service has its own root directory/image",
+                .description_bad = "Service runs within the host's root directory",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RootDirectory=",
+                .weight = 200,
+                .range = 1,
+                .assess = assess_root_directory,
+                .default_dependencies_only = true,
+        },
+        {
+                .id = "LockPersonality=",
+                .description_good = "Service cannot change ABI personality",
+                .description_bad = "Service may change ABI personality",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LockPersonality=",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, lock_personality),
+        },
+        {
+                .id = "MemoryDenyWriteExecute=",
+                .description_good = "Service cannot create writable executable memory mappings",
+                .description_bad = "Service may create writable executable memory mappings",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#MemoryDenyWriteExecute=",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, memory_deny_write_execute),
+        },
+        {
+                .id = "NoNewPrivileges=",
+                .description_good = "Service processes cannot acquire new privileges",
+                .description_bad = "Service processes may acquire new privileges",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NoNewPrivileges=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, no_new_privileges),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_ADMIN",
+                .description_good = "Service has no administrator privileges",
+                .description_bad = "Service has administrator privileges",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = UINT64_C(1) << CAP_SYS_ADMIN,
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)",
+                .description_good = "Service cannot change UID/GID identities/capabilities",
+                .description_bad = "Service may change UID/GID identities/capabilities",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SETUID)|
+                             (UINT64_C(1) << CAP_SETGID)|
+                             (UINT64_C(1) << CAP_SETPCAP),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_PTRACE",
+                .description_good = "Service has no ptrace() debugging abilities",
+                .description_bad = "Service has ptrace() debugging abilities",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_PTRACE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_TIME",
+                .description_good = "Service processes cannot change the system clock",
+                .description_bad = "Service processes may change the system clock",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = UINT64_C(1) << CAP_SYS_TIME,
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_NET_ADMIN",
+                .description_good = "Service has no network configuration privileges",
+                .description_bad = "Service has network configuration privileges",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_NET_ADMIN),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_RAWIO",
+                .description_good = "Service has no raw I/O access",
+                .description_bad = "Service has raw I/O access",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_RAWIO),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_MODULE",
+                .description_good = "Service cannot load kernel modules",
+                .description_bad = "Service may load kernel modules",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_MODULE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_AUDIT_*",
+                .description_good = "Service has no audit subsystem access",
+                .description_bad = "Service has audit subsystem access",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_AUDIT_CONTROL) |
+                             (UINT64_C(1) << CAP_AUDIT_READ) |
+                             (UINT64_C(1) << CAP_AUDIT_WRITE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYSLOG",
+                .description_good = "Service has no access to kernel logging",
+                .description_bad = "Service has access to kernel logging",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYSLOG),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE)",
+                .description_good = "Service has no privileges to change resource use parameters",
+                .description_bad = "Service has privileges to change resource use parameters",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_NICE) |
+                             (UINT64_C(1) << CAP_SYS_RESOURCE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_MKNOD",
+                .description_good = "Service cannot create device nodes",
+                .description_bad = "Service may create device nodes",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_MKNOD),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)",
+                .description_good = "Service cannot change file ownership/access mode/capabilities",
+                .description_bad = "Service may change file ownership/access mode/capabilities unrestricted",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_CHOWN) |
+                             (UINT64_C(1) << CAP_FSETID) |
+                             (UINT64_C(1) << CAP_SETFCAP),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)",
+                .description_good = "Service cannot override UNIX file/IPC permission checks",
+                .description_bad = "Service may override UNIX file/IPC permission checks",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_DAC_OVERRIDE) |
+                             (UINT64_C(1) << CAP_DAC_READ_SEARCH) |
+                             (UINT64_C(1) << CAP_FOWNER) |
+                             (UINT64_C(1) << CAP_IPC_OWNER),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_KILL",
+                .description_good = "Service cannot send UNIX signals to arbitrary processes",
+                .description_bad = "Service may send UNIX signals to arbitrary processes",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_KILL),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW)",
+                .description_good = "Service has no elevated networking privileges",
+                .description_bad = "Service has elevated networking privileges",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_NET_BIND_SERVICE) |
+                             (UINT64_C(1) << CAP_NET_BROADCAST) |
+                             (UINT64_C(1) << CAP_NET_RAW),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_BOOT",
+                .description_good = "Service cannot issue reboot()",
+                .description_bad = "Service may issue reboot()",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_BOOT),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_MAC_*",
+                .description_good = "Service cannot adjust SMACK MAC",
+                .description_bad = "Service may adjust SMACK MAC",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_MAC_ADMIN)|
+                             (UINT64_C(1) << CAP_MAC_OVERRIDE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE",
+                .description_good = "Service cannot mark files immutable",
+                .description_bad = "Service may mark files immutable",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 75,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_LINUX_IMMUTABLE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_IPC_LOCK",
+                .description_good = "Service cannot lock memory into RAM",
+                .description_bad = "Service may lock memory into RAM",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 50,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_IPC_LOCK),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_CHROOT",
+                .description_good = "Service cannot issue chroot()",
+                .description_bad = "Service may issue chroot()",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 50,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_CHROOT),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_BLOCK_SUSPEND",
+                .description_good = "Service cannot establish wake locks",
+                .description_bad = "Service may establish wake locks",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_BLOCK_SUSPEND),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_WAKE_ALARM",
+                .description_good = "Service cannot program timers that wake up the system",
+                .description_bad = "Service may program timers that wake up the system",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_WAKE_ALARM),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_LEASE",
+                .description_good = "Service cannot create file leases",
+                .description_bad = "Service may create file leases",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_LEASE),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG",
+                .description_good = "Service cannot issue vhangup()",
+                .description_bad = "Service may issue vhangup()",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_TTY_CONFIG),
+        },
+        {
+                .id = "CapabilityBoundingSet=~CAP_SYS_PACCT",
+                .description_good = "Service cannot use acct()",
+                .description_bad = "Service may use acct()",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_capability_bounding_set,
+                .parameter = (UINT64_C(1) << CAP_SYS_PACCT),
+        },
+        {
+                .id = "UMask=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#UMask=",
+                .weight = 100,
+                .range = 10,
+                .assess = assess_umask,
+        },
+        {
+                .id = "KeyringMode=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#KeyringMode=",
+                .description_good = "Service doesn't share key material with other services",
+                .description_bad = "Service shares key material with other service",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_keyring_mode,
+        },
+        {
+                .id = "NotifyAccess=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NotifyAccess=",
+                .description_good = "Service child processes cannot alter service state",
+                .description_bad = "Service child processes may alter service state",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_notify_access,
+        },
+        {
+                .id = "RemoveIPC=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RemoveIPC=",
+                .description_good = "Service user cannot leave SysV IPC objects around",
+                .description_bad = "Service user may leave SysV IPC objects around",
+                .description_na = "Service runs as root, option does not apply",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_remove_ipc,
+                .offset = offsetof(struct security_info, remove_ipc),
+        },
+        {
+                .id = "Delegate=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Delegate=",
+                .description_good = "Service does not maintain its own delegated control group subtree",
+                .description_bad = "Service maintains its own delegated control group subtree",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, delegate),
+                .parameter = true, /* invert! */
+        },
+        {
+                .id = "RestrictRealtime=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictRealtime=",
+                .description_good = "Service realtime scheduling access is restricted",
+                .description_bad = "Service may acquire realtime scheduling",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_realtime),
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWUSER",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create user namespaces",
+                .description_bad = "Service may create user namespaces",
+                .weight = 1500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWUSER,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWNS",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create file system namespaces",
+                .description_bad = "Service may create file system namespaces",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWNS,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWIPC",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create IPC namespaces",
+                .description_bad = "Service may create IPC namespaces",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWIPC,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWPID",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create process namespaces",
+                .description_bad = "Service may create process namespaces",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWPID,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWCGROUP",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create cgroup namespaces",
+                .description_bad = "Service may create cgroup namespaces",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWCGROUP,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWNET",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create network namespaces",
+                .description_bad = "Service may create network namespaces",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWNET,
+        },
+        {
+                .id = "RestrictNamespaces=~CLONE_NEWUTS",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
+                .description_good = "Service cannot create hostname namespaces",
+                .description_bad = "Service may create hostname namespaces",
+                .weight = 100,
+                .range = 1,
+                .assess = assess_restrict_namespaces,
+                .parameter = CLONE_NEWUTS,
+        },
+        {
+                .id = "RestrictAddressFamilies=~AF_(INET|INET6)",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
+                .description_good = "Service cannot allocate Internet sockets",
+                .description_bad = "Service may allocate Internet sockets",
+                .weight = 1500,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_address_family_inet),
+        },
+        {
+                .id = "RestrictAddressFamilies=~AF_UNIX",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
+                .description_good = "Service cannot allocate local sockets",
+                .description_bad = "Service may allocate local sockets",
+                .weight = 25,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_address_family_unix),
+        },
+        {
+                .id = "RestrictAddressFamilies=~AF_NETLINK",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
+                .description_good = "Service cannot allocate netlink sockets",
+                .description_bad = "Service may allocate netlink sockets",
+                .weight = 200,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_address_family_netlink),
+        },
+        {
+                .id = "RestrictAddressFamilies=~AF_PACKET",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
+                .description_good = "Service cannot allocate packet sockets",
+                .description_bad = "Service may allocate packet sockets",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_address_family_packet),
+        },
+        {
+                .id = "RestrictAddressFamilies=~…",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
+                .description_good = "Service cannot allocate exotic sockets",
+                .description_bad = "Service may allocate exotic sockets",
+                .weight = 1250,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_address_family_other),
+        },
+        {
+                .id = "SystemCallArchitectures=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallArchitectures=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_architectures,
+        },
+#if HAVE_SECCOMP
+        {
+                .id = "SystemCallFilter=~@swap",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_SWAP,
+        },
+        {
+                .id = "SystemCallFilter=~@obsolete",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 250,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_OBSOLETE,
+        },
+        {
+                .id = "SystemCallFilter=~@clock",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_CLOCK,
+        },
+        {
+                .id = "SystemCallFilter=~@cpu-emulation",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 250,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_CPU_EMULATION,
+        },
+        {
+                .id = "SystemCallFilter=~@debug",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_DEBUG,
+        },
+        {
+                .id = "SystemCallFilter=~@mount",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_MOUNT,
+        },
+        {
+                .id = "SystemCallFilter=~@module",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_MODULE,
+        },
+        {
+                .id = "SystemCallFilter=~@raw-io",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_RAW_IO,
+        },
+        {
+                .id = "SystemCallFilter=~@reboot",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_REBOOT,
+        },
+        {
+                .id = "SystemCallFilter=~@privileged",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 700,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_PRIVILEGED,
+        },
+        {
+                .id = "SystemCallFilter=~@resources",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
+                .weight = 700,
+                .range = 10,
+                .assess = assess_system_call_filter,
+                .parameter = SYSCALL_FILTER_SET_RESOURCES,
+        },
+#endif
+        {
+                .id = "IPAddressDeny=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#IPAddressDeny=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_ip_address_allow,
+        },
+        {
+                .id = "DeviceAllow=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#DeviceAllow=",
+                .weight = 1000,
+                .range = 10,
+                .assess = assess_device_allow,
+        },
+        {
+                .id = "AmbientCapabilities=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#AmbientCapabilities=",
+                .description_good = "Service process does not receive ambient capabilities",
+                .description_bad = "Service process receives ambient capabilities",
+                .weight = 500,
+                .range = 1,
+                .assess = assess_ambient_capabilities,
+        },
+};
+
+static int assess(const struct security_info *info, Table *overview_table, AnalyzeSecurityFlags flags) {
+        static const struct {
+                uint64_t exposure;
+                const char *name;
+                const char *color;
+                SpecialGlyph smiley;
+        } badness_table[] = {
+                { 100, "DANGEROUS", ANSI_HIGHLIGHT_RED,    DEPRESSED_SMILEY        },
+                { 90,  "UNSAFE",    ANSI_HIGHLIGHT_RED,    UNHAPPY_SMILEY          },
+                { 75,  "EXPOSED",   ANSI_HIGHLIGHT_YELLOW, SLIGHTLY_UNHAPPY_SMILEY },
+                { 50,  "MEDIUM",    NULL,                  NEUTRAL_SMILEY          },
+                { 10,  "OK",        ANSI_HIGHLIGHT_GREEN,  SLIGHTLY_HAPPY_SMILEY   },
+                { 1,   "SAFE",      ANSI_HIGHLIGHT_GREEN,  HAPPY_SMILEY            },
+                { 0,   "PERFECT",   ANSI_HIGHLIGHT_GREEN,  ECSTATIC_SMILEY         },
+        };
+
+        uint64_t badness_sum = 0, weight_sum = 0, exposure;
+        _cleanup_(table_unrefp) Table *details_table = NULL;
+        size_t i;
+        int r;
+
+        if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
+                details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
+                if (!details_table)
+                        return log_oom();
+
+                (void) table_set_sort(details_table, 3, 1, (size_t) -1);
+                (void) table_set_reverse(details_table, 3, true);
+
+                if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0)
+                        (void) table_set_display(details_table, 0, 1, 2, 6, (size_t) -1);
+        }
+
+        for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
+                const struct security_assessor *a = security_assessor_table + i;
+                _cleanup_free_ char *d = NULL;
+                uint64_t badness;
+                void *data;
+
+                data = (uint8_t*) info + a->offset;
+
+                if (a->default_dependencies_only && !info->default_dependencies) {
+                        badness = UINT64_MAX;
+                        d = strdup("Service runs in special boot phase, option does not apply");
+                        if (!d)
+                                return log_oom();
+                } else {
+                        r = a->assess(a, info, data, &badness, &d);
+                        if (r < 0)
+                                return r;
+                }
+
+                assert(a->range > 0);
+
+                if (badness != UINT64_MAX) {
+                        assert(badness <= a->range);
+
+                        badness_sum += DIV_ROUND_UP(badness * a->weight, a->range);
+                        weight_sum += a->weight;
+                }
+
+                if (details_table) {
+                        const char *checkmark, *description, *color = NULL;
+                        TableCell *cell;
+
+                        if (badness == UINT64_MAX) {
+                                checkmark = " ";
+                                description = a->description_na;
+                                color = NULL;
+                        } else if (badness == a->range) {
+                                checkmark = special_glyph(CROSS_MARK);
+                                description = a->description_bad;
+                                color = ansi_highlight_red();
+                        } else if (badness == 0) {
+                                checkmark = special_glyph(CHECK_MARK);
+                                description = a->description_good;
+                                color = ansi_highlight_green();
+                        } else {
+                                checkmark = special_glyph(CROSS_MARK);
+                                description = NULL;
+                                color = ansi_highlight_red();
+                        }
+
+                        if (d)
+                                description = d;
+
+                        r = table_add_cell_full(details_table, &cell, TABLE_STRING, checkmark, 1, 1, 0, 0, 0);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        if (color)
+                                (void) table_set_color(details_table, cell, color);
+
+                        r = table_add_cell(details_table, &cell, TABLE_STRING, a->id);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        if (a->url)
+                                (void) table_set_url(details_table, cell, a->url);
+
+                        r = table_add_cell(details_table, NULL, TABLE_STRING, description);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+
+                        r = table_add_cell(details_table, &cell, TABLE_UINT64, &a->weight);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        (void) table_set_align_percent(details_table, cell, 100);
+
+                        r = table_add_cell(details_table, &cell, TABLE_UINT64, &badness);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        (void) table_set_align_percent(details_table, cell, 100);
+
+                        r = table_add_cell(details_table, &cell, TABLE_UINT64, &a->range);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        (void) table_set_align_percent(details_table, cell, 100);
+
+                        r = table_add_cell(details_table, &cell, TABLE_EMPTY, NULL);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add cell to table: %m");
+                        (void) table_set_align_percent(details_table, cell, 100);
+                }
+        }
+
+        if (details_table) {
+                size_t row;
+
+                for (row = 1; row < table_get_rows(details_table); row++) {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
+                        const uint64_t *weight, *badness, *range;
+                        TableCell *cell;
+                        uint64_t x;
+
+                        assert_se(weight = table_get_at(details_table, row, 3));
+                        assert_se(badness = table_get_at(details_table, row, 4));
+                        assert_se(range = table_get_at(details_table, row, 5));
+
+                        if (*badness == UINT64_MAX || *badness == 0)
+                                continue;
+
+                        assert_se(cell = table_get_cell(details_table, row, 6));
+
+                        x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
+                        xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
+
+                        r = table_update(details_table, cell, TABLE_STRING, buf);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to update cell in table: %m");
+                }
+
+                r = table_print(details_table, stdout);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to output table: %m");
+        }
+
+        exposure = DIV_ROUND_UP(badness_sum * 100U, weight_sum);
+
+        for (i = 0; i < ELEMENTSOF(badness_table); i++)
+                if (exposure >= badness_table[i].exposure)
+                        break;
+
+        assert(i < ELEMENTSOF(badness_table));
+
+        if (details_table) {
+                _cleanup_free_ char *clickable = NULL;
+                const char *name;
+
+                /* If we shall output the details table, also print the brief summary underneath */
+
+                if (info->fragment_path) {
+                        r = terminal_urlify_path(info->fragment_path, info->id, &clickable);
+                        if (r < 0)
+                                return log_oom();
+
+                        name = clickable;
+                } else
+                        name = info->id;
+
+                printf("\n%s %sOverall exposure level for %s%s: %s%" PRIu64 ".%" PRIu64 " %s%s %s\n",
+                       special_glyph(ARROW),
+                       ansi_highlight(),
+                       name,
+                       ansi_normal(),
+                       colors_enabled() ? strempty(badness_table[i].color) : "",
+                       exposure / 10, exposure % 10,
+                       badness_table[i].name,
+                       ansi_normal(),
+                       special_glyph(badness_table[i].smiley));
+        }
+
+        fflush(stdout);
+
+        if (overview_table) {
+                char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
+                TableCell *cell;
+
+                r = table_add_cell(overview_table, &cell, TABLE_STRING, info->id);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add cell to table: %m");
+                if (info->fragment_path) {
+                        _cleanup_free_ char *url = NULL;
+
+                        r = file_url_from_path(info->fragment_path, &url);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to generate URL from path: %m");
+
+                        (void) table_set_url(overview_table, cell, url);
+                }
+
+                xsprintf(buf, "%" PRIu64 ".%" PRIu64, exposure / 10, exposure % 10);
+                r = table_add_cell(overview_table, &cell, TABLE_STRING, buf);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add cell to table: %m");
+                (void) table_set_align_percent(overview_table, cell, 100);
+
+                r = table_add_cell(overview_table, &cell, TABLE_STRING, badness_table[i].name);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add cell to table: %m");
+                (void) table_set_color(overview_table, cell, strempty(badness_table[i].color));
+
+                r = table_add_cell(overview_table, NULL, TABLE_STRING, special_glyph(badness_table[i].smiley));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add cell to table: %m");
+        }
+
+        return 0;
+}
+
+static int property_read_restrict_address_families(
+                sd_bus *bus,
+                const char *member,
+                sd_bus_message *m,
+                sd_bus_error *error,
+                void *userdata) {
+
+        struct security_info *info = userdata;
+        int whitelist, r;
+
+        assert(bus);
+        assert(member);
+        assert(m);
+
+        r = sd_bus_message_enter_container(m, 'r', "bas");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(m, "b", &whitelist);
+        if (r < 0)
+                return r;
+
+        info->restrict_address_family_inet =
+                info->restrict_address_family_unix =
+                info->restrict_address_family_netlink =
+                info->restrict_address_family_packet =
+                info->restrict_address_family_other = whitelist;
+
+        r = sd_bus_message_enter_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const char *name;
+
+                r = sd_bus_message_read(m, "s", &name);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
+                        info->restrict_address_family_inet = !whitelist;
+                else if (streq(name, "AF_UNIX"))
+                        info->restrict_address_family_unix = !whitelist;
+                else if (streq(name, "AF_NETLINK"))
+                        info->restrict_address_family_netlink = !whitelist;
+                else if (streq(name, "AF_PACKET"))
+                        info->restrict_address_family_packet = !whitelist;
+                else
+                        info->restrict_address_family_other = !whitelist;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_exit_container(m);
+}
+
+static int property_read_system_call_filter(
+                sd_bus *bus,
+                const char *member,
+                sd_bus_message *m,
+                sd_bus_error *error,
+                void *userdata) {
+
+        struct security_info *info = userdata;
+        int whitelist, r;
+
+        assert(bus);
+        assert(member);
+        assert(m);
+
+        r = sd_bus_message_enter_container(m, 'r', "bas");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(m, "b", &whitelist);
+        if (r < 0)
+                return r;
+
+        info->system_call_filter_whitelist = whitelist;
+
+        r = sd_bus_message_enter_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const char *name;
+
+                r = sd_bus_message_read(m, "s", &name);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = set_ensure_allocated(&info->system_call_filter, &string_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = set_put_strdup(info->system_call_filter, name);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_exit_container(m);
+}
+
+static int property_read_ip_address_allow(
+                sd_bus *bus,
+                const char *member,
+                sd_bus_message *m,
+                sd_bus_error *error,
+                void *userdata) {
+
+        struct security_info *info = userdata;
+        bool deny_ipv4 = false, deny_ipv6 = false;
+        int r;
+
+        assert(bus);
+        assert(member);
+        assert(m);
+
+        r = sd_bus_message_enter_container(m, 'a', "(iayu)");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const void *data;
+                size_t size;
+                int32_t family;
+                uint32_t prefixlen;
+
+                r = sd_bus_message_enter_container(m, 'r', "iayu");
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = sd_bus_message_read(m, "i", &family);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read_array(m, 'y', &data, &size);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(m, "u", &prefixlen);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(m);
+                if (r < 0)
+                        return r;
+
+                if (streq(member, "IPAddressAllow")) {
+                        union in_addr_union u;
+
+                        if (family == AF_INET && size == 4 && prefixlen == 8)
+                                memcpy(&u.in, data, size);
+                        else if (family == AF_INET6 && size == 16 && prefixlen == 128)
+                                memcpy(&u.in6, data, size);
+                        else {
+                                info->ip_address_allow_other = true;
+                                continue;
+                        }
+
+                        if (in_addr_is_localhost(family, &u))
+                                info->ip_address_allow_localhost = true;
+                        else
+                                info->ip_address_allow_other = true;
+                } else {
+                        assert(streq(member, "IPAddressDeny"));
+
+                        if (family == AF_INET && size == 4 && prefixlen == 0)
+                                deny_ipv4 = true;
+                        else if (family == AF_INET6 && size == 16 && prefixlen == 0)
+                                deny_ipv6 = true;
+                }
+        }
+
+        info->ip_address_deny_all = deny_ipv4 && deny_ipv6;
+
+        return sd_bus_message_exit_container(m);
+}
+
+static int property_read_device_allow(
+                sd_bus *bus,
+                const char *member,
+                sd_bus_message *m,
+                sd_bus_error *error,
+                void *userdata) {
+
+        struct security_info *info = userdata;
+        size_t n = 0;
+        int r;
+
+        assert(bus);
+        assert(member);
+        assert(m);
+
+        r = sd_bus_message_enter_container(m, 'a', "(ss)");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const char *name, *policy;
+
+                r = sd_bus_message_read(m, "(ss)", &name, &policy);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                n++;
+        }
+
+        info->device_allow_non_empty = n > 0;
+
+        return sd_bus_message_exit_container(m);
+}
+
+static int acquire_security_info(sd_bus *bus, const char *name, struct security_info *info, AnalyzeSecurityFlags flags) {
+
+        static const struct bus_properties_map security_map[] = {
+                { "AmbientCapabilities",     "t",       NULL,                                    offsetof(struct security_info, ambient_capabilities)      },
+                { "CapabilityBoundingSet",   "t",       NULL,                                    offsetof(struct security_info, capability_bounding_set)   },
+                { "DefaultDependencies",     "b",       NULL,                                    offsetof(struct security_info, default_dependencies)      },
+                { "Delegate",                "b",       NULL,                                    offsetof(struct security_info, delegate)                  },
+                { "DeviceAllow",             "a(ss)",   property_read_device_allow,              0                                                         },
+                { "DevicePolicy",            "s",       NULL,                                    offsetof(struct security_info, device_policy)             },
+                { "DynamicUser",             "b",       NULL,                                    offsetof(struct security_info, dynamic_user)              },
+                { "FragmentPath",            "s",       NULL,                                    offsetof(struct security_info, fragment_path)             },
+                { "IPAddressAllow",          "a(iayu)", property_read_ip_address_allow,          0                                                         },
+                { "IPAddressDeny",           "a(iayu)", property_read_ip_address_allow,          0                                                         },
+                { "Id",                      "s",       NULL,                                    offsetof(struct security_info, id)                        },
+                { "KeyringMode",             "s",       NULL,                                    offsetof(struct security_info, keyring_mode)              },
+                { "LoadState",               "s",       NULL,                                    offsetof(struct security_info, load_state)                },
+                { "LockPersonality",         "b",       NULL,                                    offsetof(struct security_info, lock_personality)          },
+                { "MemoryDenyWriteExecute",  "b",       NULL,                                    offsetof(struct security_info, memory_deny_write_execute) },
+                { "NoNewPrivileges",         "b",       NULL,                                    offsetof(struct security_info, no_new_privileges)         },
+                { "NotifyAccess",            "s",       NULL,                                    offsetof(struct security_info, notify_access)             },
+                { "PrivateDevices",          "b",       NULL,                                    offsetof(struct security_info, private_devices)           },
+                { "PrivateMounts",           "b",       NULL,                                    offsetof(struct security_info, private_mounts)            },
+                { "PrivateNetwork",          "b",       NULL,                                    offsetof(struct security_info, private_network)           },
+                { "PrivateTmp",              "b",       NULL,                                    offsetof(struct security_info, private_tmp)               },
+                { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
+                { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
+                { "ProtectControlGroups",    "b",       NULL,                                    offsetof(struct security_info, protect_control_groups)    },
+                { "ProtectHome",             "s",       NULL,                                    offsetof(struct security_info, protect_home)              },
+                { "ProtectKernelModules",    "b",       NULL,                                    offsetof(struct security_info, protect_kernel_modules)    },
+                { "ProtectKernelTunables",   "b",       NULL,                                    offsetof(struct security_info, protect_kernel_tunables)   },
+                { "ProtectSystem",           "s",       NULL,                                    offsetof(struct security_info, protect_system)            },
+                { "RemoveIPC",               "b",       NULL,                                    offsetof(struct security_info, remove_ipc)                },
+                { "RestrictAddressFamilies", "(bas)",   property_read_restrict_address_families, 0                                                         },
+                { "RestrictNamespaces",      "t",       NULL,                                    offsetof(struct security_info, restrict_namespaces)       },
+                { "RestrictRealtime",        "b",       NULL,                                    offsetof(struct security_info, restrict_realtime)         },
+                { "RootDirectory",           "s",       NULL,                                    offsetof(struct security_info, root_directory)            },
+                { "RootImage",               "s",       NULL,                                    offsetof(struct security_info, root_image)                },
+                { "SupplementaryGroups",     "as",      NULL,                                    offsetof(struct security_info, supplementary_groups)      },
+                { "SystemCallArchitectures", "as",      NULL,                                    offsetof(struct security_info, system_call_architectures) },
+                { "SystemCallFilter",        "(as)",    property_read_system_call_filter,        0                                                         },
+                { "Type",                    "s",       NULL,                                    offsetof(struct security_info, type)                      },
+                { "UMask",                   "u",       NULL,                                    offsetof(struct security_info, _umask)                    },
+                { "User",                    "s",       NULL,                                    offsetof(struct security_info, user)                      },
+                {}
+        };
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *path = NULL;
+        int r;
+
+        /* Note: this mangles *info on failure! */
+
+        assert(bus);
+        assert(name);
+        assert(info);
+
+        path = unit_dbus_path_from_name(name);
+        if (!path)
+                return log_oom();
+
+        r = bus_map_all_properties(bus,
+                                   "org.freedesktop.systemd1",
+                                   path,
+                                   security_map,
+                                   BUS_MAP_STRDUP|BUS_MAP_BOOLEAN_AS_BOOL,
+                                   &error,
+                                   NULL,
+                                   info);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get unit properties: %s", bus_error_message(&error, r));
+
+        if (!streq_ptr(info->load_state, "loaded")) {
+
+                if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LOADED))
+                        return -EMEDIUMTYPE;
+
+                if (streq_ptr(info->load_state, "not-found"))
+                        log_error("Unit %s not found, cannot analyze.", name);
+                else if (streq_ptr(info->load_state, "masked"))
+                        log_error("Unit %s is masked, cannot analyze.", name);
+                else
+                        log_error("Unit %s not loaded properly, cannot analyze.", name);
+
+                return -EINVAL;
+        }
+
+        if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LONG_RUNNING) && streq_ptr(info->type, "oneshot"))
+                return -EMEDIUMTYPE;
+
+        if (info->private_devices ||
+            info->private_tmp ||
+            info->protect_control_groups ||
+            info->protect_kernel_tunables ||
+            info->protect_kernel_modules ||
+            !streq_ptr(info->protect_home, "no") ||
+            !streq_ptr(info->protect_system, "no") ||
+            info->root_image)
+                info->private_mounts = true;
+
+        if (info->protect_kernel_modules)
+                info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE);
+
+        if (info->private_devices)
+                info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) |
+                                                   (UINT64_C(1) << CAP_SYS_RAWIO));
+
+        return 0;
+}
+
+static int analyze_security_one(sd_bus *bus, const char *name, Table* overview_table, AnalyzeSecurityFlags flags) {
+        _cleanup_(security_info_free) struct security_info info = {
+                .default_dependencies = true,
+                .capability_bounding_set = UINT64_MAX,
+                .restrict_namespaces = UINT64_MAX,
+                ._umask = 0002,
+        };
+        int r;
+
+        assert(bus);
+        assert(name);
+
+        r = acquire_security_info(bus, name, &info, flags);
+        if (r == -EMEDIUMTYPE) /* Ignore this one because not loaded or Type is oneshot */
+                return 0;
+        if (r < 0)
+                return r;
+
+        r = assess(&info, overview_table, flags);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
+        _cleanup_(table_unrefp) Table *overview_table = NULL;
+        int ret = 0, r;
+
+        assert(bus);
+
+        if (strv_length(units) != 1) {
+                overview_table = table_new("unit", "exposure", "predicate", "happy");
+                if (!overview_table)
+                        return log_oom();
+        }
+
+        if (strv_isempty(units)) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_strv_free_ char **list = NULL;
+                size_t allocated = 0, n = 0;
+                char **i;
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "ListUnits",
+                                &error, &reply,
+                                NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
+
+                r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
+                if (r < 0)
+                        return bus_log_parse_error(r);
+
+                for (;;) {
+                        UnitInfo info;
+                        char *copy = NULL;
+
+                        r = bus_parse_unit_info(reply, &info);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+                        if (r == 0)
+                                break;
+
+                        if (!endswith(info.id, ".service"))
+                                continue;
+
+                        if (!GREEDY_REALLOC(list, allocated, n+2))
+                                return log_oom();
+
+                        copy = strdup(info.id);
+                        if (!copy)
+                                return log_oom();
+
+                        list[n++] = copy;
+                        list[n] = NULL;
+                }
+
+                strv_sort(list);
+
+                flags |= ANALYZE_SECURITY_SHORT|ANALYZE_SECURITY_ONLY_LOADED|ANALYZE_SECURITY_ONLY_LONG_RUNNING;
+
+                STRV_FOREACH(i, list) {
+                        r = analyze_security_one(bus, *i, overview_table, flags);
+                        if (r < 0 && ret >= 0)
+                                ret = r;
+                }
+
+        } else {
+                char **i;
+
+                STRV_FOREACH(i, units) {
+                        _cleanup_free_ char *mangled = NULL, *instance = NULL;
+                        const char *name;
+
+                        if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT) && i != units) {
+                                putc('\n', stdout);
+                                fflush(stdout);
+                        }
+
+                        r = unit_name_mangle_with_suffix(*i, 0, ".service", &mangled);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to mangle unit name '%s': %m", *i);
+
+                        if (!endswith(mangled, ".service")) {
+                                log_error("Unit %s is not a service unit, refusing.", *i);
+                                return -EINVAL;
+                        }
+
+                        if (unit_name_is_valid(mangled, UNIT_NAME_TEMPLATE)) {
+                                r = unit_name_replace_instance(mangled, "test-instance", &instance);
+                                if (r < 0)
+                                        return log_oom();
+
+                                name = instance;
+                        } else
+                                name = mangled;
+
+                        r = analyze_security_one(bus, name, overview_table, flags);
+                        if (r < 0 && ret >= 0)
+                                ret = r;
+                }
+        }
+
+        if (overview_table) {
+                if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
+                        putc('\n', stdout);
+                        fflush(stdout);
+                }
+
+                r = table_print(overview_table, stdout);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to output table: %m");
+        }
+
+        return ret;
+}
diff --git a/src/analyze/analyze-security.h b/src/analyze/analyze-security.h
new file mode 100644 (file)
index 0000000..c00ae7c
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+
+typedef enum AnalyzeSecurityFlags {
+        ANALYZE_SECURITY_SHORT             = 1 << 0,
+        ANALYZE_SECURITY_ONLY_LOADED       = 1 << 1,
+        ANALYZE_SECURITY_ONLY_LONG_RUNNING = 1 << 2,
+} AnalyzeSecurityFlags;
+
+int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags);
index 42f2a8f3452260543931d1344a4295f88b88c4dc..1d8a1ed7b3249f3d2624241df02df43806cf7802 100644 (file)
@@ -43,10 +43,7 @@ static int prepare_filename(const char *filename, char **ret) {
         if (!dir)
                 return -ENOMEM;
 
-        if (with_instance)
-                c = path_join(NULL, dir, with_instance);
-        else
-                c = path_join(NULL, dir, name);
+        c = path_join(dir, with_instance ?: name);
         if (!c)
                 return -ENOMEM;
 
index 62c62ca526567bacca93ffd1faedb7ce5a79ef73..2b9cb65256d96353caa17806c066d031641aa06d 100644 (file)
 #include "sd-bus.h"
 
 #include "alloc-util.h"
+#include "analyze-security.h"
 #include "analyze-verify.h"
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
 #include "calendarspec.h"
-#include "def.h"
 #include "conf-files.h"
 #include "copy.h"
+#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "glob-util.h"
@@ -169,7 +170,7 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in
                         't', val);
 
         if (r < 0)
-                return log_error_errno(r, "Failed to parse reply: %s", bus_error_message(&error, -r));
+                return log_error_errno(r, "Failed to parse reply: %s", bus_error_message(&error, r));
 
         return 0;
 }
@@ -192,7 +193,7 @@ static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char
                         &error,
                         strv);
         if (r < 0)
-                return log_error_errno(r, "Failed to get unit property %s: %s", property, bus_error_message(&error, -r));
+                return log_error_errno(r, "Failed to get unit property %s: %s", property, bus_error_message(&error, r));
 
         return 0;
 }
@@ -355,7 +356,7 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
                         &error, &reply,
                         NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, -r));
+                return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
         if (r < 0)
@@ -978,7 +979,7 @@ static int list_dependencies(sd_bus *bus, const char *name) {
                         &reply,
                         "s");
         if (r < 0)
-                return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, -r));
+                return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_read(reply, "s", &id);
         if (r < 0)
@@ -1238,7 +1239,7 @@ static int dot(int argc, char *argv[], void *userdata) {
                        &reply,
                        "");
         if (r < 0)
-                log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, -r));
+                log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
         if (r < 0)
@@ -1340,15 +1341,16 @@ static int dump(int argc, char *argv[], void *userdata) {
 }
 
 static int cat_config(int argc, char *argv[], void *userdata) {
-        char **arg;
+        char **arg, **list;
         int r;
 
         (void) pager_open(arg_pager_flags);
 
-        STRV_FOREACH(arg, argv + 1) {
+        list = strv_skip(argv, 1);
+        STRV_FOREACH(arg, list) {
                 const char *t = NULL;
 
-                if (arg != argv + 1)
+                if (arg != list)
                         print_separator();
 
                 if (path_is_absolute(*arg)) {
@@ -1783,6 +1785,19 @@ static int do_verify(int argc, char *argv[], void *userdata) {
         return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators);
 }
 
+static int do_security(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        r = acquire_bus(&bus, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create bus connection: %m");
+
+        (void) pager_open(arg_pager_flags);
+
+        return analyze_security(bus, strv_skip(argv, 1), 0);
+}
+
 static int help(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -1827,6 +1842,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  calendar SPEC...         Validate repetitive calendar time events\n"
                "  service-watchdogs [BOOL] Get/set service watchdog state\n"
                "  timespan SPAN...         Validate a time span\n"
+               "  security [UNIT...]       Analyze security of unit\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , link
@@ -2014,6 +2030,7 @@ static int run(int argc, char *argv[]) {
                 { "calendar",          2,        VERB_ANY, 0,            test_calendar          },
                 { "service-watchdogs", VERB_ANY, 2,        0,            service_watchdogs      },
                 { "timespan",          2,        VERB_ANY, 0,            dump_timespan          },
+                { "security",          VERB_ANY, VERB_ANY, 0,            do_security            },
                 {}
         };
 
index 3a69a259b1143439798a9a15518a46919c402d03..4db4dfa5526ad72bc38e05538e6e318a18702c25 100644 (file)
@@ -4,4 +4,6 @@ systemd_analyze_sources = files('''
         analyze.c
         analyze-verify.c
         analyze-verify.h
+        analyze-security.c
+        analyze-security.h
 '''.split())
index cf03dfc6d3911f90e81d9f18f5a43c967397a2a1..abad221d58a8afa54df906420cf1e3a1428504b7 100644 (file)
@@ -17,7 +17,7 @@ const char *af_to_name(int id) {
         if (id <= 0)
                 return NULL;
 
-        if (id >= (int) ELEMENTSOF(af_names))
+        if ((size_t) id >= ELEMENTSOF(af_names))
                 return NULL;
 
         return af_names[id];
index 2a6deb12ca0936b3ef996b2855ff75b553135e64..7d237720b985f08692e8f948281b2b4f5669d7a8 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "macro.h"
 
+typedef void (*free_func_t)(void *p);
+
 #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
 
 #define new0(t, n) ((t*) calloc((n), sizeof(t)))
index a6b8fa9d84bfaf731193e98f1cd8b3ff28115ec5..b6e2486b67b393f6c65edb39c8552784a94931f5 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "arphrd-list.h"
 #include "macro.h"
+#include "missing_network.h"
 
 static const struct arphrd_name* lookup_arphrd(register const char *str, register GPERF_LEN_TYPE len);
 
@@ -17,7 +18,7 @@ const char *arphrd_to_name(int id) {
         if (id <= 0)
                 return NULL;
 
-        if (id >= (int) ELEMENTSOF(arphrd_names))
+        if ((size_t) id >= ELEMENTSOF(arphrd_names))
                 return NULL;
 
         return arphrd_names[id];
index 42b311eccd1573ee6b851f0cc9846cd4cc939a02..3017ecd55d399cfe0af36d159331c7725d490412 100644 (file)
 #include "fd-util.h"
 #include "fileio.h"
 #include "missing.h"
+#include "parse-util.h"
 #include "stat-util.h"
 
 int block_get_whole_disk(dev_t d, dev_t *ret) {
         char p[SYS_BLOCK_PATH_MAX("/partition")];
         _cleanup_free_ char *s = NULL;
-        unsigned n, m;
+        dev_t devt;
         int r;
 
         assert(ret);
@@ -38,16 +39,16 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
         if (r < 0)
                 return r;
 
-        r = sscanf(s, "%u:%u", &m, &n);
-        if (r != 2)
-                return -EINVAL;
+        r = parse_dev(s, &devt);
+        if (r < 0)
+                return r;
 
         /* Only return this if it is really good enough for us. */
-        xsprintf_sys_block_path(p, "/queue", makedev(m, n));
+        xsprintf_sys_block_path(p, "/queue", devt);
         if (access(p, F_OK) < 0)
                 return -ENOENT;
 
-        *ret = makedev(m, n);
+        *ret = devt;
         return 0;
 }
 
@@ -85,8 +86,8 @@ int block_get_originating(dev_t dt, dev_t *ret) {
         _cleanup_free_ char *t = NULL;
         char p[SYS_BLOCK_PATH_MAX("/slaves")];
         struct dirent *de, *found = NULL;
-        unsigned maj, min;
         const char *q;
+        dev_t devt;
         int r;
 
         /* For the specified block device tries to chase it through the layers, in case LUKS-style DM stacking is used,
@@ -148,13 +149,14 @@ int block_get_originating(dev_t dt, dev_t *ret) {
         if (r < 0)
                 return r;
 
-        if (sscanf(t, "%u:%u", &maj, &min) != 2)
+        r = parse_dev(t, &devt);
+        if (r < 0)
                 return -EINVAL;
 
-        if (maj == 0)
+        if (major(devt) == 0)
                 return -ENOENT;
 
-        *ret = makedev(maj, min);
+        *ret = devt;
         return 1;
 }
 
diff --git a/src/basic/btrfs-ctree.h b/src/basic/btrfs-ctree.h
deleted file mode 100644 (file)
index c5a4244..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-#pragma once
-
-#include "macro.h"
-#include "missing.h"
-#include "sparse-endian.h"
-
-/* Stolen from btrfs' ctree.h */
-
-struct btrfs_timespec {
-        le64_t sec;
-        le32_t nsec;
-} _packed_;
-
-struct btrfs_disk_key {
-        le64_t objectid;
-        uint8_t type;
-        le64_t offset;
-} _packed_;
-
-struct btrfs_inode_item {
-        le64_t generation;
-        le64_t transid;
-        le64_t size;
-        le64_t nbytes;
-        le64_t block_group;
-        le32_t nlink;
-        le32_t uid;
-        le32_t gid;
-        le32_t mode;
-        le64_t rdev;
-        le64_t flags;
-        le64_t sequence;
-        le64_t reserved[4];
-        struct btrfs_timespec atime;
-        struct btrfs_timespec ctime;
-        struct btrfs_timespec mtime;
-        struct btrfs_timespec otime;
-} _packed_;
-
-struct btrfs_root_item {
-        struct btrfs_inode_item inode;
-        le64_t generation;
-        le64_t root_dirid;
-        le64_t bytenr;
-        le64_t byte_limit;
-        le64_t bytes_used;
-        le64_t last_snapshot;
-        le64_t flags;
-        le32_t refs;
-        struct btrfs_disk_key drop_progress;
-        uint8_t drop_level;
-        uint8_t level;
-        le64_t generation_v2;
-        uint8_t uuid[BTRFS_UUID_SIZE];
-        uint8_t parent_uuid[BTRFS_UUID_SIZE];
-        uint8_t received_uuid[BTRFS_UUID_SIZE];
-        le64_t ctransid;
-        le64_t otransid;
-        le64_t stransid;
-        le64_t rtransid;
-        struct btrfs_timespec ctime;
-        struct btrfs_timespec otime;
-        struct btrfs_timespec stime;
-        struct btrfs_timespec rtime;
-        le64_t reserved[8];
-} _packed_;
-
-#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0)
-
-struct btrfs_qgroup_info_item {
-        le64_t generation;
-        le64_t rfer;
-        le64_t rfer_cmpr;
-        le64_t excl;
-        le64_t excl_cmpr;
-} _packed_;
-
-#define BTRFS_QGROUP_LIMIT_MAX_RFER     (1ULL << 0)
-#define BTRFS_QGROUP_LIMIT_MAX_EXCL     (1ULL << 1)
-#define BTRFS_QGROUP_LIMIT_RSV_RFER     (1ULL << 2)
-#define BTRFS_QGROUP_LIMIT_RSV_EXCL     (1ULL << 3)
-#define BTRFS_QGROUP_LIMIT_RFER_CMPR    (1ULL << 4)
-#define BTRFS_QGROUP_LIMIT_EXCL_CMPR    (1ULL << 5)
-
-struct btrfs_qgroup_limit_item {
-        le64_t flags;
-        le64_t max_rfer;
-        le64_t max_excl;
-        le64_t rsv_rfer;
-        le64_t rsv_excl;
-} _packed_;
-
-struct btrfs_root_ref {
-        le64_t dirid;
-        le64_t sequence;
-        le16_t name_len;
-} _packed_;
index 48e819a7cbeac33c31dde8605798de2ec8767af0..d08e7546d0173f63ddbfd127a6df8216f391701d 100644 (file)
 #include <sys/sysmacros.h>
 #include <unistd.h>
 
-#if HAVE_LINUX_BTRFS_H
-#include <linux/btrfs.h>
-#endif
-
 #include "alloc-util.h"
 #include "blockdev-util.h"
-#include "btrfs-ctree.h"
 #include "btrfs-util.h"
 #include "chattr-util.h"
 #include "copy.h"
@@ -870,96 +865,6 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u
         return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max);
 }
 
-int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
-        struct btrfs_ioctl_vol_args args = {};
-        char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")], q[DEV_NUM_PATH_MAX];
-        _cleanup_free_ char *backing = NULL;
-        _cleanup_close_ int loop_fd = -1, backing_fd = -1;
-        struct stat st;
-        dev_t dev = 0;
-        int r;
-
-        /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
-        if (!FILE_SIZE_VALID(new_size))
-                return -EINVAL;
-
-        /* btrfs cannot handle file systems < 16M, hence use this as minimum */
-        if (new_size < 16*1024*1024)
-                new_size = 16*1024*1024;
-
-        r = btrfs_get_block_device_fd(fd, &dev);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -ENODEV;
-
-        xsprintf_sys_block_path(p, "/loop/backing_file", dev);
-        r = read_one_line_file(p, &backing);
-        if (r == -ENOENT)
-                return -ENODEV;
-        if (r < 0)
-                return r;
-        if (isempty(backing) || !path_is_absolute(backing))
-                return -ENODEV;
-
-        backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
-        if (backing_fd < 0)
-                return -errno;
-
-        if (fstat(backing_fd, &st) < 0)
-                return -errno;
-        if (!S_ISREG(st.st_mode))
-                return -ENODEV;
-
-        if (new_size == (uint64_t) st.st_size)
-                return 0;
-
-        if (grow_only && new_size < (uint64_t) st.st_size)
-                return -EINVAL;
-
-        xsprintf_dev_num_path(q, "block", dev);
-        loop_fd = open(q, O_RDWR|O_CLOEXEC|O_NOCTTY);
-        if (loop_fd < 0)
-                return -errno;
-
-        if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
-                return -EINVAL;
-
-        if (new_size < (uint64_t) st.st_size) {
-                /* Decrease size: first decrease btrfs size, then shorten loopback */
-                if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
-                        return -errno;
-        }
-
-        if (ftruncate(backing_fd, new_size) < 0)
-                return -errno;
-
-        if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
-                return -errno;
-
-        if (new_size > (uint64_t) st.st_size) {
-                /* Increase size: first enlarge loopback, then increase btrfs size */
-                if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
-                        return -errno;
-        }
-
-        /* Make sure the free disk space is correctly updated for both file systems */
-        (void) fsync(fd);
-        (void) fsync(backing_fd);
-
-        return 1;
-}
-
-int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
-        _cleanup_close_ int fd = -1;
-
-        fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        return btrfs_resize_loopback_fd(fd, new_size, grow_only);
-}
-
 int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) {
         assert(ret);
 
@@ -1503,7 +1408,12 @@ static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_s
         return changed;
 }
 
-static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
+static int subvol_snapshot_children(
+                int old_fd,
+                int new_fd,
+                const char *subvolume,
+                uint64_t old_subvol_id,
+                BtrfsSnapshotFlags flags) {
 
         struct btrfs_ioctl_search_args args = {
                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
@@ -1683,7 +1593,14 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
         return 0;
 }
 
-int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
+int btrfs_subvol_snapshot_fd_full(
+                int old_fd,
+                const char *new_path,
+                BtrfsSnapshotFlags flags,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         _cleanup_close_ int new_fd = -1;
         const char *subvolume;
         int r;
@@ -1711,7 +1628,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
                 } else if (r < 0)
                         return r;
 
-                r = copy_directory_fd(old_fd, new_path, COPY_MERGE|COPY_REFLINK);
+                r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK, progress_path, progress_bytes, userdata);
                 if (r < 0)
                         goto fallback_fail;
 
@@ -1748,7 +1665,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
         return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
 }
 
-int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
+int btrfs_subvol_snapshot_full(
+                const char *old_path,
+                const char *new_path,
+                BtrfsSnapshotFlags flags,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         _cleanup_close_ int old_fd = -1;
 
         assert(old_path);
@@ -1758,7 +1682,7 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnaps
         if (old_fd < 0)
                 return -errno;
 
-        return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
+        return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, progress_path, progress_bytes, userdata);
 }
 
 int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
index b0cf6739f7755b77fd53ef5b6740a494d67f4794..085aca4dbcb271353d65023ec1cb838b2c571fec 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "sd-id128.h"
 
+#include "copy.h"
 #include "time-util.h"
 
 typedef struct BtrfsSubvolInfo {
@@ -61,14 +62,18 @@ int btrfs_quota_scan_start(int fd);
 int btrfs_quota_scan_wait(int fd);
 int btrfs_quota_scan_ongoing(int fd);
 
-int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
-int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
-
 int btrfs_subvol_make(const char *path);
 int btrfs_subvol_make_fd(int fd, const char *subvolume);
 
-int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
-int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
+int btrfs_subvol_snapshot_fd_full(int old_fd, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
+        return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, NULL, NULL, NULL);
+}
+
+int btrfs_subvol_snapshot_full(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
+        return btrfs_subvol_snapshot_full(old_path, new_path, flags, NULL, NULL, NULL);
+}
 
 int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
 int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
index bfcda335201a675e8f3d2b34508b7a60eff70539..29a17d9320e36fb4bd796ec3c112d61637923ee3 100644 (file)
@@ -22,7 +22,7 @@ const char *capability_to_name(int id) {
         if (id < 0)
                 return NULL;
 
-        if (id >= (int) ELEMENTSOF(capability_names))
+        if ((size_t) id >= ELEMENTSOF(capability_names))
                 return NULL;
 
         return capability_names[id];
@@ -37,7 +37,7 @@ int capability_from_name(const char *name) {
         /* Try to parse numeric capability */
         r = safe_atoi(name, &i);
         if (r >= 0) {
-                if (i >= 0 && i < (int) ELEMENTSOF(capability_names))
+                if (i >= 0 && (size_t) i < ELEMENTSOF(capability_names))
                         return i;
                 else
                         return -EINVAL;
index 6ae35e078b3a296c1963cb25028e22050a9f752f..a3f3ca9f52b9663d28ca9d51d436ba631f906b01 100644 (file)
@@ -359,3 +359,128 @@ bool ambient_capabilities_supported(void) {
 
         return cache;
 }
+
+int capability_quintet_enforce(const CapabilityQuintet *q) {
+        _cleanup_cap_free_ cap_t c = NULL;
+        int r;
+
+        if (q->ambient != (uint64_t) -1) {
+                unsigned long i;
+                bool changed = false;
+
+                c = cap_get_proc();
+                if (!c)
+                        return -errno;
+
+                /* In order to raise the ambient caps set we first need to raise the matching inheritable + permitted
+                 * cap */
+                for (i = 0; i <= cap_last_cap(); i++) {
+                        uint64_t m = UINT64_C(1) << i;
+                        cap_value_t cv = (cap_value_t) i;
+                        cap_flag_value_t old_value_inheritable, old_value_permitted;
+
+                        if ((q->ambient & m) == 0)
+                                continue;
+
+                        if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value_inheritable) < 0)
+                                return -errno;
+                        if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value_permitted) < 0)
+                                return -errno;
+
+                        if (old_value_inheritable == CAP_SET && old_value_permitted == CAP_SET)
+                                continue;
+
+                        if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0)
+                                return -errno;
+
+                        if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
+                                return -errno;
+
+                        changed = true;
+                }
+
+                if (changed)
+                        if (cap_set_proc(c) < 0)
+                                return -errno;
+
+                r = capability_ambient_set_apply(q->ambient, false);
+                if (r < 0)
+                        return r;
+        }
+
+        if (q->inheritable != (uint64_t) -1 || q->permitted != (uint64_t) -1 || q->effective != (uint64_t) -1) {
+                bool changed = false;
+                unsigned long i;
+
+                if (!c) {
+                        c = cap_get_proc();
+                        if (!c)
+                                return -errno;
+                }
+
+                for (i = 0; i <= cap_last_cap(); i++) {
+                        uint64_t m = UINT64_C(1) << i;
+                        cap_value_t cv = (cap_value_t) i;
+
+                        if (q->inheritable != (uint64_t) -1) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0)
+                                        return -errno;
+
+                                new_value = (q->inheritable & m) ? CAP_SET : CAP_CLEAR;
+
+                                if (old_value != new_value) {
+                                        changed = true;
+
+                                        if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, new_value) < 0)
+                                                return -errno;
+                                }
+                        }
+
+                        if (q->permitted != (uint64_t) -1) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0)
+                                        return -errno;
+
+                                new_value = (q->permitted & m) ? CAP_SET : CAP_CLEAR;
+
+                                if (old_value != new_value) {
+                                        changed = true;
+
+                                        if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, new_value) < 0)
+                                                return -errno;
+                                }
+                        }
+
+                        if (q->effective != (uint64_t) -1) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0)
+                                        return -errno;
+
+                                new_value = (q->effective & m) ? CAP_SET : CAP_CLEAR;
+
+                                if (old_value != new_value) {
+                                        changed = true;
+
+                                        if (cap_set_flag(c, CAP_EFFECTIVE, 1, &cv, new_value) < 0)
+                                                return -errno;
+                                }
+                        }
+                }
+
+                if (changed)
+                        if (cap_set_proc(c) < 0)
+                                return -errno;
+        }
+
+        if (q->bounding != (uint64_t) -1) {
+                r = capability_bounding_set_drop(q->bounding, false);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
index 59591d4b521eb56039b11a0bf62d0eae2f410e90..02c7d5c3e2e2d815ffe096cfb0a854a80e27ec31 100644 (file)
@@ -7,6 +7,7 @@
 #include <sys/types.h>
 
 #include "macro.h"
+#include "missing_capability.h"
 #include "util.h"
 
 #define CAP_ALL (uint64_t) -1
@@ -43,3 +44,27 @@ bool ambient_capabilities_supported(void);
 /* Identical to linux/capability.h's CAP_TO_MASK(), but uses an unsigned 1U instead of a signed 1 for shifting left, in
  * order to avoid complaints about shifting a signed int left by 31 bits, which would make it negative. */
 #define CAP_TO_MASK_CORRECTED(x) (1U << ((x) & 31U))
+
+typedef struct CapabilityQuintet {
+        /* Stores all five types of capabilities in one go. Note that we use (uint64_t) -1 for unset here. This hence
+         * needs to be updated as soon as Linux learns more than 63 caps. */
+        uint64_t effective;
+        uint64_t bounding;
+        uint64_t inheritable;
+        uint64_t permitted;
+        uint64_t ambient;
+} CapabilityQuintet;
+
+assert_cc(CAP_LAST_CAP < 64);
+
+#define CAPABILITY_QUINTET_NULL { (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1 }
+
+static inline bool capability_quintet_is_set(const CapabilityQuintet *q) {
+        return q->effective != (uint64_t) -1 ||
+                q->bounding != (uint64_t) -1 ||
+                q->inheritable != (uint64_t) -1 ||
+                q->permitted != (uint64_t) -1 ||
+                q->ambient != (uint64_t) -1;
+}
+
+int capability_quintet_enforce(const CapabilityQuintet *q);
index 7b44ae277d7e88a11a1f825627282d125268d349..76750606b43004b95a740fa092a2bbac52ca8628 100644 (file)
@@ -189,11 +189,12 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
          * - do nothing if our new entry matches the existing entry,
          * - replace the existing entry if our new entry has higher priority.
          */
-        size_t i;
+        size_t i, n;
         char *t;
         int r;
 
-        for (i = 0; i < strv_length(*strv); i++) {
+        n = strv_length(*strv);
+        for (i = 0; i < n; i++) {
                 int c;
 
                 c = base_cmp((char* const*) *strv + i, (char* const*) &path);
@@ -216,7 +217,7 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
                                 p2 = path_startswith(path, *dir);
                                 if (p2) {
                                         /* Our new entry has higher priority */
-                                        t = path_join(root, path, NULL);
+                                        t = path_join(root, path);
                                         if (!t)
                                                 return log_oom();
 
@@ -232,26 +233,15 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
                 /* … we are not there yet, let's continue */
         }
 
-        t = path_join(root, path, NULL);
+        t = path_join(root, path);
         if (!t)
-                return log_oom();
+                return -ENOMEM;
 
         r = strv_insert(strv, i, t);
         if (r < 0)
                 free(t);
-        return r;
-}
-
-int conf_files_insert_nulstr(char ***strv, const char *root, const char *dirs, const char *path) {
-        _cleanup_strv_free_ char **d = NULL;
-
-        assert(strv);
-
-        d = strv_split_nulstr(dirs);
-        if (!d)
-                return -ENOMEM;
 
-        return conf_files_insert(strv, root, d, path);
+        return r;
 }
 
 int conf_files_list_strv(char ***strv, const char *suffix, const char *root, unsigned flags, const char* const* dirs) {
@@ -318,7 +308,7 @@ int conf_files_list_with_replacement(
                 if (r < 0)
                         return log_error_errno(r, "Failed to extend config file list: %m");
 
-                p = path_join(root, replacement, NULL);
+                p = path_join(root, replacement);
                 if (!p)
                         return log_oom();
         }
index f31f17de9d6017bfd291ba6bbaee60828681175f..55ab32640202a9ee194792040cd5ef2be7abd2ae 100644 (file)
@@ -15,7 +15,6 @@ int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned
 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);
 int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path);
-int conf_files_insert_nulstr(char ***strv, const char *root, const char *dirs, const char *path);
 int conf_files_list_with_replacement(
                 const char *root,
                 char **config_dirs,
index 3efd9041c0a6b0cc5ad8456618e7575caea080e6..34e01ea1cf4dbdaada79542ded53d9c3287dfaba 100644 (file)
 #include "copy.h"
 #include "dirent-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "io-util.h"
 #include "macro.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
+#include "tmpfile-util.h"
 #include "umask-util.h"
 #include "user-util.h"
 #include "xattr-util.h"
@@ -90,7 +90,9 @@ int copy_bytes_full(
                 uint64_t max_bytes,
                 CopyFlags copy_flags,
                 void **ret_remains,
-                size_t *ret_remains_size) {
+                size_t *ret_remains_size,
+                copy_progress_bytes_t progress,
+                void *userdata) {
 
         bool try_cfr = true, try_sendfile = true, try_splice = true;
         int r, nonblock_pipe = -1;
@@ -161,8 +163,6 @@ int copy_bytes_full(
                                                 return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */
                                         }
                                 }
-
-                                log_debug_errno(r, "Reflinking didn't work, falling back to non-reflink copying: %m");
                         }
                 }
         }
@@ -308,10 +308,17 @@ int copy_bytes_full(
                 }
 
         next:
+                if (progress) {
+                        r = progress(n, userdata);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (max_bytes != (uint64_t) -1) {
                         assert(max_bytes >= (uint64_t) n);
                         max_bytes -= n;
                 }
+
                 /* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
                  * so reduce our maximum by the amount we already copied,
                  * but don't go below our copy buffer size, unless we are
@@ -363,7 +370,9 @@ static int fd_copy_regular(
                 const char *to,
                 uid_t override_uid,
                 gid_t override_gid,
-                CopyFlags copy_flags) {
+                CopyFlags copy_flags,
+                copy_progress_bytes_t progress,
+                void *userdata) {
 
         _cleanup_close_ int fdf = -1, fdt = -1;
         struct timespec ts[2];
@@ -381,7 +390,7 @@ static int fd_copy_regular(
         if (fdt < 0)
                 return -errno;
 
-        r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
+        r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress, userdata);
         if (r < 0) {
                 (void) unlinkat(dt, to, 0);
                 return r;
@@ -483,7 +492,11 @@ static int fd_copy_directory(
                 unsigned depth_left,
                 uid_t override_uid,
                 gid_t override_gid,
-                CopyFlags copy_flags) {
+                CopyFlags copy_flags,
+                const char *display_path,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
 
         _cleanup_close_ int fdf = -1, fdt = -1;
         _cleanup_closedir_ DIR *d = NULL;
@@ -524,6 +537,8 @@ static int fd_copy_directory(
         r = 0;
 
         FOREACH_DIRENT_ALL(de, d, return -errno) {
+                const char *child_display_path = NULL;
+                _cleanup_free_ char *dp = NULL;
                 struct stat buf;
                 int q;
 
@@ -535,6 +550,17 @@ static int fd_copy_directory(
                         continue;
                 }
 
+                if (progress_path) {
+                        if (display_path)
+                                child_display_path = dp = strjoin(display_path, "/", de->d_name);
+                        else
+                                child_display_path = de->d_name;
+
+                        r = progress_path(child_display_path, &buf, userdata);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (S_ISDIR(buf.st_mode)) {
                         /*
                          * Don't descend into directories on other file systems, if this is requested. We do a simple
@@ -566,9 +592,9 @@ static int fd_copy_directory(
                                         continue;
                         }
 
-                        q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags);
+                        q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, child_display_path, progress_path, progress_bytes, userdata);
                 } else if (S_ISREG(buf.st_mode))
-                        q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
+                        q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, progress_bytes, userdata);
                 else if (S_ISLNK(buf.st_mode))
                         q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
                 else if (S_ISFIFO(buf.st_mode))
@@ -606,7 +632,18 @@ static int fd_copy_directory(
         return r;
 }
 
-int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
+int copy_tree_at_full(
+                int fdf,
+                const char *from,
+                int fdt,
+                const char *to,
+                uid_t override_uid,
+                gid_t override_gid,
+                CopyFlags copy_flags,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         struct stat st;
 
         assert(from);
@@ -616,9 +653,9 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t overr
                 return -errno;
 
         if (S_ISREG(st.st_mode))
-                return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
+                return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, progress_bytes, userdata);
         else if (S_ISDIR(st.st_mode))
-                return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags);
+                return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, progress_path, progress_bytes, userdata);
         else if (S_ISLNK(st.st_mode))
                 return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
         else if (S_ISFIFO(st.st_mode))
@@ -629,11 +666,14 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t overr
                 return -EOPNOTSUPP;
 }
 
-int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
-        return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags);
-}
+int copy_directory_fd_full(
+                int dirfd,
+                const char *to,
+                CopyFlags copy_flags,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
 
-int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
         struct stat st;
 
         assert(dirfd >= 0);
@@ -645,10 +685,17 @@ int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
 
-        return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags);
+        return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata);
 }
 
-int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
+int copy_directory_full(
+                const char *from,
+                const char *to,
+                CopyFlags copy_flags,
+                copy_progress_path_t progress_path,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         struct stat st;
 
         assert(from);
@@ -660,10 +707,16 @@ int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
 
-        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags);
+        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata);
 }
 
-int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
+int copy_file_fd_full(
+                const char *from,
+                int fdt,
+                CopyFlags copy_flags,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         _cleanup_close_ int fdf = -1;
         int r;
 
@@ -674,7 +727,7 @@ int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
         if (fdf < 0)
                 return -errno;
 
-        r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
+        r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata);
 
         (void) copy_times(fdf, fdt);
         (void) copy_xattr(fdf, fdt);
@@ -682,7 +735,16 @@ int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
         return r;
 }
 
-int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
+int copy_file_full(
+                const char *from,
+                const char *to,
+                int flags,
+                mode_t mode,
+                unsigned chattr_flags,
+                CopyFlags copy_flags,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         int fdt = -1, r;
 
         assert(from);
@@ -697,7 +759,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
         if (chattr_flags != 0)
                 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
 
-        r = copy_file_fd(from, fdt, copy_flags);
+        r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
         if (r < 0) {
                 close(fdt);
                 (void) unlink(to);
@@ -712,7 +774,15 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
         return 0;
 }
 
-int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
+int copy_file_atomic_full(
+                const char *from,
+                const char *to,
+                mode_t mode,
+                unsigned chattr_flags,
+                CopyFlags copy_flags,
+                copy_progress_bytes_t progress_bytes,
+                void *userdata) {
+
         _cleanup_(unlink_and_freep) char *t = NULL;
         _cleanup_close_ int fdt = -1;
         int r;
@@ -745,7 +815,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned cha
         if (chattr_flags != 0)
                 (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
 
-        r = copy_file_fd(from, fdt, copy_flags);
+        r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
         if (r < 0)
                 return r;
 
index 6a0a6bc9b399418f97d15085dfc05c5a337186ae..a41b44c70ab9a82477e74a5463c1e55f15cd7cd0 100644 (file)
@@ -1,9 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <fcntl.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 
 typedef enum CopyFlags {
@@ -13,16 +15,46 @@ typedef enum CopyFlags {
         COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
 } CopyFlags;
 
-int copy_file_fd(const char *from, int to, CopyFlags copy_flags);
-int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
-int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
-int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags);
-int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags);
-int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags);
-int copy_directory(const char *from, const char *to, CopyFlags copy_flags);
-int copy_bytes_full(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, size_t *ret_remains_size);
+typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
+typedef int (*copy_progress_path_t)(const char *path, const struct stat *st, void *userdata);
+
+int copy_file_fd_full(const char *from, int to, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
+static inline int copy_file_fd(const char *from, int to, CopyFlags copy_flags) {
+        return copy_file_fd_full(from, to, copy_flags, NULL, NULL);
+}
+
+int copy_file_full(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
+static inline int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
+        return copy_file_full(from, to, open_flags, mode, chattr_flags, copy_flags, NULL, NULL);
+}
+
+int copy_file_atomic_full(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
+static inline int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
+        return copy_file_atomic_full(from, to, mode, chattr_flags, copy_flags, NULL, NULL);
+}
+
+int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
+        return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL);
+}
+static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
+        return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL);
+}
+
+int copy_directory_fd_full(int dirfd, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
+        return copy_directory_fd_full(dirfd, to, copy_flags, NULL, NULL, NULL);
+}
+
+int copy_directory_full(const char *from, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
+        return copy_directory_full(from, to, copy_flags, NULL, NULL, NULL);
+}
+
+int copy_bytes_full(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, size_t *ret_remains_size, copy_progress_bytes_t progress, void *userdata);
 static inline int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
-        return copy_bytes_full(fdf, fdt, max_bytes, copy_flags, NULL, NULL);
+        return copy_bytes_full(fdf, fdt, max_bytes, copy_flags, NULL, NULL, NULL, NULL);
 }
+
 int copy_times(int fdf, int fdt);
 int copy_xattr(int fdf, int fdt);
diff --git a/src/basic/env-file.c b/src/basic/env-file.c
new file mode 100644 (file)
index 0000000..6a7d674
--- /dev/null
@@ -0,0 +1,574 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdio_ext.h>
+
+#include "alloc-util.h"
+#include "env-file.h"
+#include "env-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tmpfile-util.h"
+#include "utf8.h"
+
+static int parse_env_file_internal(
+                FILE *f,
+                const char *fname,
+                int (*push) (const char *filename, unsigned line,
+                             const char *key, char *value, void *userdata, int *n_pushed),
+                void *userdata,
+                int *n_pushed) {
+
+        size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
+        _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
+        unsigned line = 1;
+        char *p;
+        int r;
+
+        enum {
+                PRE_KEY,
+                KEY,
+                PRE_VALUE,
+                VALUE,
+                VALUE_ESCAPE,
+                SINGLE_QUOTE_VALUE,
+                SINGLE_QUOTE_VALUE_ESCAPE,
+                DOUBLE_QUOTE_VALUE,
+                DOUBLE_QUOTE_VALUE_ESCAPE,
+                COMMENT,
+                COMMENT_ESCAPE
+        } state = PRE_KEY;
+
+        if (f)
+                r = read_full_stream(f, &contents, NULL);
+        else
+                r = read_full_file(fname, &contents, NULL);
+        if (r < 0)
+                return r;
+
+        for (p = contents; *p; p++) {
+                char c = *p;
+
+                switch (state) {
+
+                case PRE_KEY:
+                        if (strchr(COMMENTS, c))
+                                state = COMMENT;
+                        else if (!strchr(WHITESPACE, c)) {
+                                state = KEY;
+                                last_key_whitespace = (size_t) -1;
+
+                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
+                                        return -ENOMEM;
+
+                                key[n_key++] = c;
+                        }
+                        break;
+
+                case KEY:
+                        if (strchr(NEWLINE, c)) {
+                                state = PRE_KEY;
+                                line++;
+                                n_key = 0;
+                        } else if (c == '=') {
+                                state = PRE_VALUE;
+                                last_value_whitespace = (size_t) -1;
+                        } else {
+                                if (!strchr(WHITESPACE, c))
+                                        last_key_whitespace = (size_t) -1;
+                                else if (last_key_whitespace == (size_t) -1)
+                                         last_key_whitespace = n_key;
+
+                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
+                                        return -ENOMEM;
+
+                                key[n_key++] = c;
+                        }
+
+                        break;
+
+                case PRE_VALUE:
+                        if (strchr(NEWLINE, c)) {
+                                state = PRE_KEY;
+                                line++;
+                                key[n_key] = 0;
+
+                                if (value)
+                                        value[n_value] = 0;
+
+                                /* strip trailing whitespace from key */
+                                if (last_key_whitespace != (size_t) -1)
+                                        key[last_key_whitespace] = 0;
+
+                                r = push(fname, line, key, value, userdata, n_pushed);
+                                if (r < 0)
+                                        return r;
+
+                                n_key = 0;
+                                value = NULL;
+                                value_alloc = n_value = 0;
+
+                        } else if (c == '\'')
+                                state = SINGLE_QUOTE_VALUE;
+                        else if (c == '\"')
+                                state = DOUBLE_QUOTE_VALUE;
+                        else if (c == '\\')
+                                state = VALUE_ESCAPE;
+                        else if (!strchr(WHITESPACE, c)) {
+                                state = VALUE;
+
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return  -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+
+                        break;
+
+                case VALUE:
+                        if (strchr(NEWLINE, c)) {
+                                state = PRE_KEY;
+                                line++;
+
+                                key[n_key] = 0;
+
+                                if (value)
+                                        value[n_value] = 0;
+
+                                /* Chomp off trailing whitespace from value */
+                                if (last_value_whitespace != (size_t) -1)
+                                        value[last_value_whitespace] = 0;
+
+                                /* strip trailing whitespace from key */
+                                if (last_key_whitespace != (size_t) -1)
+                                        key[last_key_whitespace] = 0;
+
+                                r = push(fname, line, key, value, userdata, n_pushed);
+                                if (r < 0)
+                                        return r;
+
+                                n_key = 0;
+                                value = NULL;
+                                value_alloc = n_value = 0;
+
+                        } else if (c == '\\') {
+                                state = VALUE_ESCAPE;
+                                last_value_whitespace = (size_t) -1;
+                        } else {
+                                if (!strchr(WHITESPACE, c))
+                                        last_value_whitespace = (size_t) -1;
+                                else if (last_value_whitespace == (size_t) -1)
+                                        last_value_whitespace = n_value;
+
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+
+                        break;
+
+                case VALUE_ESCAPE:
+                        state = VALUE;
+
+                        if (!strchr(NEWLINE, c)) {
+                                /* Escaped newlines we eat up entirely */
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+                        break;
+
+                case SINGLE_QUOTE_VALUE:
+                        if (c == '\'')
+                                state = PRE_VALUE;
+                        else if (c == '\\')
+                                state = SINGLE_QUOTE_VALUE_ESCAPE;
+                        else {
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+
+                        break;
+
+                case SINGLE_QUOTE_VALUE_ESCAPE:
+                        state = SINGLE_QUOTE_VALUE;
+
+                        if (!strchr(NEWLINE, c)) {
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+                        break;
+
+                case DOUBLE_QUOTE_VALUE:
+                        if (c == '\"')
+                                state = PRE_VALUE;
+                        else if (c == '\\')
+                                state = DOUBLE_QUOTE_VALUE_ESCAPE;
+                        else {
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+
+                        break;
+
+                case DOUBLE_QUOTE_VALUE_ESCAPE:
+                        state = DOUBLE_QUOTE_VALUE;
+
+                        if (!strchr(NEWLINE, c)) {
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+                                        return -ENOMEM;
+
+                                value[n_value++] = c;
+                        }
+                        break;
+
+                case COMMENT:
+                        if (c == '\\')
+                                state = COMMENT_ESCAPE;
+                        else if (strchr(NEWLINE, c)) {
+                                state = PRE_KEY;
+                                line++;
+                        }
+                        break;
+
+                case COMMENT_ESCAPE:
+                        state = COMMENT;
+                        break;
+                }
+        }
+
+        if (IN_SET(state,
+                   PRE_VALUE,
+                   VALUE,
+                   VALUE_ESCAPE,
+                   SINGLE_QUOTE_VALUE,
+                   SINGLE_QUOTE_VALUE_ESCAPE,
+                   DOUBLE_QUOTE_VALUE,
+                   DOUBLE_QUOTE_VALUE_ESCAPE)) {
+
+                key[n_key] = 0;
+
+                if (value)
+                        value[n_value] = 0;
+
+                if (state == VALUE)
+                        if (last_value_whitespace != (size_t) -1)
+                                value[last_value_whitespace] = 0;
+
+                /* strip trailing whitespace from key */
+                if (last_key_whitespace != (size_t) -1)
+                        key[last_key_whitespace] = 0;
+
+                r = push(fname, line, key, value, userdata, n_pushed);
+                if (r < 0)
+                        return r;
+
+                value = NULL;
+        }
+
+        return 0;
+}
+
+static int check_utf8ness_and_warn(
+                const char *filename, unsigned line,
+                const char *key, char *value) {
+
+        if (!utf8_is_valid(key)) {
+                _cleanup_free_ char *p = NULL;
+
+                p = utf8_escape_invalid(key);
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s:%u: invalid UTF-8 in key '%s', ignoring.",
+                                       strna(filename), line, p);
+        }
+
+        if (value && !utf8_is_valid(value)) {
+                _cleanup_free_ char *p = NULL;
+
+                p = utf8_escape_invalid(value);
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
+                                       strna(filename), line, key, p);
+        }
+
+        return 0;
+}
+
+static int parse_env_file_push(
+                const char *filename, unsigned line,
+                const char *key, char *value,
+                void *userdata,
+                int *n_pushed) {
+
+        const char *k;
+        va_list aq, *ap = userdata;
+        int r;
+
+        r = check_utf8ness_and_warn(filename, line, key, value);
+        if (r < 0)
+                return r;
+
+        va_copy(aq, *ap);
+
+        while ((k = va_arg(aq, const char *))) {
+                char **v;
+
+                v = va_arg(aq, char **);
+
+                if (streq(key, k)) {
+                        va_end(aq);
+                        free(*v);
+                        *v = value;
+
+                        if (n_pushed)
+                                (*n_pushed)++;
+
+                        return 1;
+                }
+        }
+
+        va_end(aq);
+        free(value);
+
+        return 0;
+}
+
+int parse_env_filev(
+                FILE *f,
+                const char *fname,
+                va_list ap) {
+
+        int r, n_pushed = 0;
+        va_list aq;
+
+        va_copy(aq, ap);
+        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
+        va_end(aq);
+        if (r < 0)
+                return r;
+
+        return n_pushed;
+}
+
+int parse_env_file_sentinel(
+                FILE *f,
+                const char *fname,
+                ...) {
+
+        va_list ap;
+        int r;
+
+        va_start(ap, fname);
+        r = parse_env_filev(f, fname, ap);
+        va_end(ap);
+
+        return r;
+}
+
+static int load_env_file_push(
+                const char *filename, unsigned line,
+                const char *key, char *value,
+                void *userdata,
+                int *n_pushed) {
+        char ***m = userdata;
+        char *p;
+        int r;
+
+        r = check_utf8ness_and_warn(filename, line, key, value);
+        if (r < 0)
+                return r;
+
+        p = strjoin(key, "=", value);
+        if (!p)
+                return -ENOMEM;
+
+        r = strv_env_replace(m, p);
+        if (r < 0) {
+                free(p);
+                return r;
+        }
+
+        if (n_pushed)
+                (*n_pushed)++;
+
+        free(value);
+        return 0;
+}
+
+int load_env_file(FILE *f, const char *fname, char ***rl) {
+        char **m = NULL;
+        int r;
+
+        r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
+        if (r < 0) {
+                strv_free(m);
+                return r;
+        }
+
+        *rl = m;
+        return 0;
+}
+
+static int load_env_file_push_pairs(
+                const char *filename, unsigned line,
+                const char *key, char *value,
+                void *userdata,
+                int *n_pushed) {
+        char ***m = userdata;
+        int r;
+
+        r = check_utf8ness_and_warn(filename, line, key, value);
+        if (r < 0)
+                return r;
+
+        r = strv_extend(m, key);
+        if (r < 0)
+                return -ENOMEM;
+
+        if (!value) {
+                r = strv_extend(m, "");
+                if (r < 0)
+                        return -ENOMEM;
+        } else {
+                r = strv_push(m, value);
+                if (r < 0)
+                        return r;
+        }
+
+        if (n_pushed)
+                (*n_pushed)++;
+
+        return 0;
+}
+
+int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
+        char **m = NULL;
+        int r;
+
+        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
+        if (r < 0) {
+                strv_free(m);
+                return r;
+        }
+
+        *rl = m;
+        return 0;
+}
+
+static int merge_env_file_push(
+                const char *filename, unsigned line,
+                const char *key, char *value,
+                void *userdata,
+                int *n_pushed) {
+
+        char ***env = userdata;
+        char *expanded_value;
+
+        assert(env);
+
+        if (!value) {
+                log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
+                return 0;
+        }
+
+        if (!env_name_is_valid(key)) {
+                log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
+                free(value);
+                return 0;
+        }
+
+        expanded_value = replace_env(value, *env,
+                                     REPLACE_ENV_USE_ENVIRONMENT|
+                                     REPLACE_ENV_ALLOW_BRACELESS|
+                                     REPLACE_ENV_ALLOW_EXTENDED);
+        if (!expanded_value)
+                return -ENOMEM;
+
+        free_and_replace(value, expanded_value);
+
+        return load_env_file_push(filename, line, key, value, env, n_pushed);
+}
+
+int merge_env_file(
+                char ***env,
+                FILE *f,
+                const char *fname) {
+
+        /* NOTE: this function supports braceful and braceless variable expansions,
+         * plus "extended" substitutions, unlike other exported parsing functions.
+         */
+
+        return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
+}
+
+static void write_env_var(FILE *f, const char *v) {
+        const char *p;
+
+        p = strchr(v, '=');
+        if (!p) {
+                /* Fallback */
+                fputs_unlocked(v, f);
+                fputc_unlocked('\n', f);
+                return;
+        }
+
+        p++;
+        fwrite_unlocked(v, 1, p-v, f);
+
+        if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
+                fputc_unlocked('\"', f);
+
+                for (; *p; p++) {
+                        if (strchr(SHELL_NEED_ESCAPE, *p))
+                                fputc_unlocked('\\', f);
+
+                        fputc_unlocked(*p, f);
+                }
+
+                fputc_unlocked('\"', f);
+        } else
+                fputs_unlocked(p, f);
+
+        fputc_unlocked('\n', f);
+}
+
+int write_env_file(const char *fname, char **l) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        char **i;
+        int r;
+
+        assert(fname);
+
+        r = fopen_temporary(fname, &f, &p);
+        if (r < 0)
+                return r;
+
+        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+        (void) fchmod_umask(fileno(f), 0644);
+
+        STRV_FOREACH(i, l)
+                write_env_var(f, *i);
+
+        r = fflush_and_check(f);
+        if (r >= 0) {
+                if (rename(p, fname) >= 0)
+                        return 0;
+
+                r = -errno;
+        }
+
+        unlink(p);
+        return r;
+}
diff --git a/src/basic/env-file.h b/src/basic/env-file.h
new file mode 100644 (file)
index 0000000..e1ca195
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "macro.h"
+
+int parse_env_filev(FILE *f, const char *fname, va_list ap);
+int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
+#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
+int load_env_file(FILE *f, const char *fname, char ***l);
+int load_env_file_pairs(FILE *f, const char *fname, char ***l);
+
+int merge_env_file(char ***env, FILE *f, const char *fname);
+
+int write_env_file(const char *fname, char **l);
index 1b72bbf3ad9a8fdbb95fdfddf28db7eec0a61db9..44cc57053966a6cdb0cce16ca9125401a56e5ec8 100644 (file)
@@ -17,7 +17,7 @@ const char *errno_to_name(int id) {
         if (id < 0)
                 id = -id;
 
-        if (id >= (int) ELEMENTSOF(errno_names))
+        if ((size_t) id >= ELEMENTSOF(errno_names))
                 return NULL;
 
         return errno_names[id];
index 2e07c73b9ede8236ee0e230fccda48ef9c2835ca..515620993d051b4df03074acf3f5736937053ee0 100644 (file)
@@ -8,7 +8,7 @@
 #include <uchar.h>
 
 #include "string-util.h"
-#include "missing.h"
+#include "missing_type.h"
 
 /* What characters are special in the shell? */
 /* must be escaped outside and inside double-quotes */
index 461ace73e2147411c50dbb668347f138ac346a60..e875696a1a9ea26e066ecf724949460d4b0f8a8c 100644 (file)
@@ -28,21 +28,15 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
         return buffer;
 }
 
-int ether_addr_compare(const void *a, const void *b) {
-        assert(a);
-        assert(b);
-
+int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
         return memcmp(a, b, ETH_ALEN);
 }
 
-static void ether_addr_hash_func(const void *p, struct siphash *state) {
+static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
         siphash24_compress(p, sizeof(struct ether_addr), state);
 }
 
-const struct hash_ops ether_addr_hash_ops = {
-        .hash = ether_addr_hash_func,
-        .compare = ether_addr_compare
-};
+DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
 
 int ether_addr_from_string(const char *s, struct ether_addr *ret) {
         size_t pos = 0, n, field;
index 3be0370049b07a2efb9c61af3e9da35aa66372c3..4e44b30be98e6fbb7f097e03002baa47d01077e6 100644 (file)
@@ -12,7 +12,7 @@
 #define ETHER_ADDR_TO_STRING_MAX (3*6)
 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
 
-int ether_addr_compare(const void *a, const void *b);
+int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b);
 static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
         return ether_addr_compare(a, b) == 0;
 }
index 5775a13e3e8067298195143d9ba8b88ae35eb98c..c06f2fac7e80dc8f44996d711a7bae5537ffc9c5 100644 (file)
@@ -23,6 +23,7 @@
 #include "socket-util.h"
 #include "stdio-util.h"
 #include "util.h"
+#include "tmpfile-util.h"
 
 int close_nointr(int fd) {
         assert(fd >= 0);
@@ -113,7 +114,7 @@ FILE* safe_fclose(FILE *f) {
         if (f) {
                 PROTECT_ERRNO;
 
-                assert_se(fclose_nointr(f) != EBADF);
+                assert_se(fclose_nointr(f) != -EBADF);
         }
 
         return NULL;
@@ -648,7 +649,7 @@ int fd_duplicate_data_fd(int fd) {
 
                         if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
 
-                                r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size);
+                                r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
                                 if (r < 0 && r != -EAGAIN)
                                         return r; /* If we get EAGAIN it could be because of the source or because of
                                                    * the destination fd, we can't know, as sendfile() and friends won't
index 5e771a0aaeccbb9e617dfe63b99852066e93ff53..4c200f8393e8315637df0c563b13e0725eb06647 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -8,32 +9,22 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
-#include "ctype.h"
-#include "env-util.h"
-#include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
-#include "hexdecoct.h"
 #include "log.h"
 #include "macro.h"
 #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"
-#include "strv.h"
-#include "time-util.h"
-#include "umask-util.h"
-#include "utf8.h"
+#include "tmpfile-util.h"
 
 #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
 
@@ -364,565 +355,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
         return read_full_stream(f, contents, size);
 }
 
-static int parse_env_file_internal(
-                FILE *f,
-                const char *fname,
-                int (*push) (const char *filename, unsigned line,
-                             const char *key, char *value, void *userdata, int *n_pushed),
-                void *userdata,
-                int *n_pushed) {
-
-        size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
-        _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
-        unsigned line = 1;
-        char *p;
-        int r;
-
-        enum {
-                PRE_KEY,
-                KEY,
-                PRE_VALUE,
-                VALUE,
-                VALUE_ESCAPE,
-                SINGLE_QUOTE_VALUE,
-                SINGLE_QUOTE_VALUE_ESCAPE,
-                DOUBLE_QUOTE_VALUE,
-                DOUBLE_QUOTE_VALUE_ESCAPE,
-                COMMENT,
-                COMMENT_ESCAPE
-        } state = PRE_KEY;
-
-        if (f)
-                r = read_full_stream(f, &contents, NULL);
-        else
-                r = read_full_file(fname, &contents, NULL);
-        if (r < 0)
-                return r;
-
-        for (p = contents; *p; p++) {
-                char c = *p;
-
-                switch (state) {
-
-                case PRE_KEY:
-                        if (strchr(COMMENTS, c))
-                                state = COMMENT;
-                        else if (!strchr(WHITESPACE, c)) {
-                                state = KEY;
-                                last_key_whitespace = (size_t) -1;
-
-                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
-                                        return -ENOMEM;
-
-                                key[n_key++] = c;
-                        }
-                        break;
-
-                case KEY:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                                n_key = 0;
-                        } else if (c == '=') {
-                                state = PRE_VALUE;
-                                last_value_whitespace = (size_t) -1;
-                        } else {
-                                if (!strchr(WHITESPACE, c))
-                                        last_key_whitespace = (size_t) -1;
-                                else if (last_key_whitespace == (size_t) -1)
-                                         last_key_whitespace = n_key;
-
-                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
-                                        return -ENOMEM;
-
-                                key[n_key++] = c;
-                        }
-
-                        break;
-
-                case PRE_VALUE:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                                key[n_key] = 0;
-
-                                if (value)
-                                        value[n_value] = 0;
-
-                                /* strip trailing whitespace from key */
-                                if (last_key_whitespace != (size_t) -1)
-                                        key[last_key_whitespace] = 0;
-
-                                r = push(fname, line, key, value, userdata, n_pushed);
-                                if (r < 0)
-                                        return r;
-
-                                n_key = 0;
-                                value = NULL;
-                                value_alloc = n_value = 0;
-
-                        } else if (c == '\'')
-                                state = SINGLE_QUOTE_VALUE;
-                        else if (c == '\"')
-                                state = DOUBLE_QUOTE_VALUE;
-                        else if (c == '\\')
-                                state = VALUE_ESCAPE;
-                        else if (!strchr(WHITESPACE, c)) {
-                                state = VALUE;
-
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return  -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case VALUE:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-
-                                key[n_key] = 0;
-
-                                if (value)
-                                        value[n_value] = 0;
-
-                                /* Chomp off trailing whitespace from value */
-                                if (last_value_whitespace != (size_t) -1)
-                                        value[last_value_whitespace] = 0;
-
-                                /* strip trailing whitespace from key */
-                                if (last_key_whitespace != (size_t) -1)
-                                        key[last_key_whitespace] = 0;
-
-                                r = push(fname, line, key, value, userdata, n_pushed);
-                                if (r < 0)
-                                        return r;
-
-                                n_key = 0;
-                                value = NULL;
-                                value_alloc = n_value = 0;
-
-                        } else if (c == '\\') {
-                                state = VALUE_ESCAPE;
-                                last_value_whitespace = (size_t) -1;
-                        } else {
-                                if (!strchr(WHITESPACE, c))
-                                        last_value_whitespace = (size_t) -1;
-                                else if (last_value_whitespace == (size_t) -1)
-                                        last_value_whitespace = n_value;
-
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case VALUE_ESCAPE:
-                        state = VALUE;
-
-                        if (!strchr(NEWLINE, c)) {
-                                /* Escaped newlines we eat up entirely */
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-                        break;
-
-                case SINGLE_QUOTE_VALUE:
-                        if (c == '\'')
-                                state = PRE_VALUE;
-                        else if (c == '\\')
-                                state = SINGLE_QUOTE_VALUE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case SINGLE_QUOTE_VALUE_ESCAPE:
-                        state = SINGLE_QUOTE_VALUE;
-
-                        if (!strchr(NEWLINE, c)) {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-                        break;
-
-                case DOUBLE_QUOTE_VALUE:
-                        if (c == '\"')
-                                state = PRE_VALUE;
-                        else if (c == '\\')
-                                state = DOUBLE_QUOTE_VALUE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case DOUBLE_QUOTE_VALUE_ESCAPE:
-                        state = DOUBLE_QUOTE_VALUE;
-
-                        if (!strchr(NEWLINE, c)) {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-                        break;
-
-                case COMMENT:
-                        if (c == '\\')
-                                state = COMMENT_ESCAPE;
-                        else if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                        }
-                        break;
-
-                case COMMENT_ESCAPE:
-                        state = COMMENT;
-                        break;
-                }
-        }
-
-        if (IN_SET(state,
-                   PRE_VALUE,
-                   VALUE,
-                   VALUE_ESCAPE,
-                   SINGLE_QUOTE_VALUE,
-                   SINGLE_QUOTE_VALUE_ESCAPE,
-                   DOUBLE_QUOTE_VALUE,
-                   DOUBLE_QUOTE_VALUE_ESCAPE)) {
-
-                key[n_key] = 0;
-
-                if (value)
-                        value[n_value] = 0;
-
-                if (state == VALUE)
-                        if (last_value_whitespace != (size_t) -1)
-                                value[last_value_whitespace] = 0;
-
-                /* strip trailing whitespace from key */
-                if (last_key_whitespace != (size_t) -1)
-                        key[last_key_whitespace] = 0;
-
-                r = push(fname, line, key, value, userdata, n_pushed);
-                if (r < 0)
-                        return r;
-
-                value = NULL;
-        }
-
-        return 0;
-}
-
-static int check_utf8ness_and_warn(
-                const char *filename, unsigned line,
-                const char *key, char *value) {
-
-        if (!utf8_is_valid(key)) {
-                _cleanup_free_ char *p = NULL;
-
-                p = utf8_escape_invalid(key);
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s:%u: invalid UTF-8 in key '%s', ignoring.",
-                                       strna(filename), line, p);
-        }
-
-        if (value && !utf8_is_valid(value)) {
-                _cleanup_free_ char *p = NULL;
-
-                p = utf8_escape_invalid(value);
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
-                                       strna(filename), line, key, p);
-        }
-
-        return 0;
-}
-
-static int parse_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-
-        const char *k;
-        va_list aq, *ap = userdata;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        va_copy(aq, *ap);
-
-        while ((k = va_arg(aq, const char *))) {
-                char **v;
-
-                v = va_arg(aq, char **);
-
-                if (streq(key, k)) {
-                        va_end(aq);
-                        free(*v);
-                        *v = value;
-
-                        if (n_pushed)
-                                (*n_pushed)++;
-
-                        return 1;
-                }
-        }
-
-        va_end(aq);
-        free(value);
-
-        return 0;
-}
-
-int parse_env_filev(
-                FILE *f,
-                const char *fname,
-                va_list ap) {
-
-        int r, n_pushed = 0;
-        va_list aq;
-
-        va_copy(aq, ap);
-        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
-        va_end(aq);
-        if (r < 0)
-                return r;
-
-        return n_pushed;
-}
-
-int parse_env_file_sentinel(
-                FILE *f,
-                const char *fname,
-                ...) {
-
-        va_list ap;
-        int r;
-
-        va_start(ap, fname);
-        r = parse_env_filev(f, fname, ap);
-        va_end(ap);
-
-        return r;
-}
-
-static int load_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-        char ***m = userdata;
-        char *p;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        p = strjoin(key, "=", value);
-        if (!p)
-                return -ENOMEM;
-
-        r = strv_env_replace(m, p);
-        if (r < 0) {
-                free(p);
-                return r;
-        }
-
-        if (n_pushed)
-                (*n_pushed)++;
-
-        free(value);
-        return 0;
-}
-
-int load_env_file(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
-        int r;
-
-        r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
-                return r;
-        }
-
-        *rl = m;
-        return 0;
-}
-
-static int load_env_file_push_pairs(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-        char ***m = userdata;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        r = strv_extend(m, key);
-        if (r < 0)
-                return -ENOMEM;
-
-        if (!value) {
-                r = strv_extend(m, "");
-                if (r < 0)
-                        return -ENOMEM;
-        } else {
-                r = strv_push(m, value);
-                if (r < 0)
-                        return r;
-        }
-
-        if (n_pushed)
-                (*n_pushed)++;
-
-        return 0;
-}
-
-int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
-        int r;
-
-        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
-                return r;
-        }
-
-        *rl = m;
-        return 0;
-}
-
-static int merge_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-
-        char ***env = userdata;
-        char *expanded_value;
-
-        assert(env);
-
-        if (!value) {
-                log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
-                return 0;
-        }
-
-        if (!env_name_is_valid(key)) {
-                log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
-                free(value);
-                return 0;
-        }
-
-        expanded_value = replace_env(value, *env,
-                                     REPLACE_ENV_USE_ENVIRONMENT|
-                                     REPLACE_ENV_ALLOW_BRACELESS|
-                                     REPLACE_ENV_ALLOW_EXTENDED);
-        if (!expanded_value)
-                return -ENOMEM;
-
-        free_and_replace(value, expanded_value);
-
-        return load_env_file_push(filename, line, key, value, env, n_pushed);
-}
-
-int merge_env_file(
-                char ***env,
-                FILE *f,
-                const char *fname) {
-
-        /* NOTE: this function supports braceful and braceless variable expansions,
-         * plus "extended" substitutions, unlike other exported parsing functions.
-         */
-
-        return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
-}
-
-static void write_env_var(FILE *f, const char *v) {
-        const char *p;
-
-        p = strchr(v, '=');
-        if (!p) {
-                /* Fallback */
-                fputs_unlocked(v, f);
-                fputc_unlocked('\n', f);
-                return;
-        }
-
-        p++;
-        fwrite_unlocked(v, 1, p-v, f);
-
-        if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
-                fputc_unlocked('\"', f);
-
-                for (; *p; p++) {
-                        if (strchr(SHELL_NEED_ESCAPE, *p))
-                                fputc_unlocked('\\', f);
-
-                        fputc_unlocked(*p, f);
-                }
-
-                fputc_unlocked('\"', f);
-        } else
-                fputs_unlocked(p, f);
-
-        fputc_unlocked('\n', f);
-}
-
-int write_env_file(const char *fname, char **l) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *p = NULL;
-        char **i;
-        int r;
-
-        assert(fname);
-
-        r = fopen_temporary(fname, &f, &p);
-        if (r < 0)
-                return r;
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-        (void) fchmod_umask(fileno(f), 0644);
-
-        STRV_FOREACH(i, l)
-                write_env_var(f, *i);
-
-        r = fflush_and_check(f);
-        if (r >= 0) {
-                if (rename(p, fname) >= 0)
-                        return 0;
-
-                r = -errno;
-        }
-
-        unlink(p);
-        return r;
-}
-
 int executable_is_script(const char *path, char **interpreter) {
         _cleanup_free_ char *line = NULL;
         size_t len;
@@ -1128,39 +560,6 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
         return search_and_fopen_internal(path, mode, root, s, _f);
 }
 
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
-        FILE *f;
-        char *t;
-        int r, fd;
-
-        assert(path);
-        assert(_f);
-        assert(_temp_path);
-
-        r = tempfn_xxxxxx(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        fd = mkostemp_safe(t);
-        if (fd < 0) {
-                free(t);
-                return -errno;
-        }
-
-        f = fdopen(fd, "we");
-        if (!f) {
-                unlink_noerrno(t);
-                free(t);
-                safe_close(fd);
-                return -errno;
-        }
-
-        *_f = f;
-        *_temp_path = t;
-
-        return 0;
-}
-
 int fflush_and_check(FILE *f) {
         assert(f);
 
@@ -1192,163 +591,6 @@ int fflush_sync_and_check(FILE *f) {
         return 0;
 }
 
-/* This is much like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern) {
-        _cleanup_umask_ mode_t u = 0;
-        int fd;
-
-        assert(pattern);
-
-        u = umask(077);
-
-        fd = mkostemp(pattern, O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
-        int fd;
-        FILE *f;
-
-        fd = mkostemp_safe(pattern);
-        if (fd < 0)
-                return fd;
-
-        f = fdopen(fd, mode);
-        if (!f) {
-                safe_close(fd);
-                return -errno;
-        }
-
-        *ret_f = f;
-        return 0;
-}
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t;
-
-        assert(ret);
-
-        if (isempty(p))
-                return -EINVAL;
-        if (path_equal(p, "/"))
-                return -EINVAL;
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldoXXXXXX
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
-int tempfn_random(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-
-        assert(ret);
-
-        if (isempty(p))
-                return -EINVAL;
-        if (path_equal(p, "/"))
-                return -EINVAL;
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldobaa2a261115984a9
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
-int tempfn_random_child(const char *p, const char *extra, char **ret) {
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-        int r;
-
-        assert(ret);
-
-        /* Turns this:
-         *         /foo/bar/waldo
-         * Into this:
-         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
-         */
-
-        if (!p) {
-                r = tmp_dir(&p);
-                if (r < 0)
-                        return r;
-        }
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        if (isempty(p))
-                x = stpcpy(stpcpy(t, ".#"), extra);
-        else
-                x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
 int write_timestamp_file_atomic(const char *fn, usec_t n) {
         char ln[DECIMAL_STR_MAX(n)+2];
 
@@ -1412,119 +654,6 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
         return fputs(s, f);
 }
 
-int open_tmpfile_unlinkable(const char *directory, int flags) {
-        char *p;
-        int fd, r;
-
-        if (!directory) {
-                r = tmp_dir(&directory);
-                if (r < 0)
-                        return r;
-        } else if (isempty(directory))
-                return -EINVAL;
-
-        /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
-
-        /* Try O_TMPFILE first, if it is supported */
-        fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
-        if (fd >= 0)
-                return fd;
-
-        /* Fall back to unguessable name + unlinking */
-        p = strjoina(directory, "/systemd-tmp-XXXXXX");
-
-        fd = mkostemp_safe(p);
-        if (fd < 0)
-                return fd;
-
-        (void) unlink(p);
-
-        return fd;
-}
-
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
-        _cleanup_free_ char *tmp = NULL;
-        int r, fd;
-
-        assert(target);
-        assert(ret_path);
-
-        /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
-        assert((flags & O_EXCL) == 0);
-
-        /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
-         * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
-         * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
-
-        fd = open_parent(target, O_TMPFILE|flags, 0640);
-        if (fd >= 0) {
-                *ret_path = NULL;
-                return fd;
-        }
-
-        log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
-
-        r = tempfn_random(target, NULL, &tmp);
-        if (r < 0)
-                return r;
-
-        fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
-        if (fd < 0)
-                return -errno;
-
-        *ret_path = TAKE_PTR(tmp);
-
-        return fd;
-}
-
-int open_serialization_fd(const char *ident) {
-        int fd = -1;
-
-        fd = memfd_create(ident, MFD_CLOEXEC);
-        if (fd < 0) {
-                const char *path;
-
-                path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
-                fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
-                if (fd < 0)
-                        return fd;
-
-                log_debug("Serializing %s to %s.", ident, path);
-        } else
-                log_debug("Serializing %s to memfd.", ident);
-
-        return fd;
-}
-
-int link_tmpfile(int fd, const char *path, const char *target) {
-        int r;
-
-        assert(fd >= 0);
-        assert(target);
-
-        /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
-         * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
-         * on the directory, and renameat2() is used instead.
-         *
-         * Note that in both cases we will not replace existing files. This is because linkat() does not support this
-         * operation currently (renameat2() does), and there is no nice way to emulate this. */
-
-        if (path) {
-                r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
-                if (r < 0)
-                        return r;
-        } else {
-                char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
-
-                xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
-
-                if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
-                        return -errno;
-        }
-
-        return 0;
-}
-
 int read_nul_string(FILE *f, char **ret) {
         _cleanup_free_ char *x = NULL;
         size_t allocated = 0, n = 0;
@@ -1565,33 +694,6 @@ int read_nul_string(FILE *f, char **ret) {
         return 0;
 }
 
-int mkdtemp_malloc(const char *template, char **ret) {
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(ret);
-
-        if (template)
-                p = strdup(template);
-        else {
-                const char *tmp;
-
-                r = tmp_dir(&tmp);
-                if (r < 0)
-                        return r;
-
-                p = strjoin(tmp, "/XXXXXX");
-        }
-        if (!p)
-                return -ENOMEM;
-
-        if (!mkdtemp(p))
-                return -errno;
-
-        *ret = TAKE_PTR(p);
-        return 0;
-}
-
 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
 
 int read_line(FILE *f, size_t limit, char **ret) {
index dae115e3bbc83fe7a64b38b0e066c792ecb3495b..8480246072222491faed37ea2fe9bd91d191b4e2 100644 (file)
@@ -44,16 +44,6 @@ int read_full_stream(FILE *f, char **contents, size_t *size);
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
 
-int parse_env_filev(FILE *f, const char *fname, va_list ap);
-int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
-#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
-int load_env_file(FILE *f, const char *fname, char ***l);
-int load_env_file_pairs(FILE *f, const char *fname, char ***l);
-
-int merge_env_file(char ***env, FILE *f, const char *fname);
-
-int write_env_file(const char *fname, char **l);
-
 int executable_is_script(const char *path, char **interpreter);
 
 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
@@ -66,27 +56,11 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
 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);
-int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
-int tempfn_random(const char *p, const char *extra, char **ret);
-int tempfn_random_child(const char *p, const char *extra, char **ret);
-
 int write_timestamp_file_atomic(const char *fn, usec_t n);
 int read_timestamp_file(const char *fn, usec_t *ret);
 
 int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
 
-int open_tmpfile_unlinkable(const char *directory, int flags);
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
-int open_serialization_fd(const char *ident);
-
-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);
index ac97c803d08ab2c8c8d9b79f737217c87a79bfb9..06bae8decf438150a16cb93b885111803cf12426 100644 (file)
@@ -13,7 +13,6 @@
 #include "alloc-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "locale-util.h"
 #include "log.h"
@@ -28,6 +27,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -212,31 +212,62 @@ int readlink_and_make_absolute(const char *p, char **r) {
 }
 
 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+        char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+        _cleanup_close_ int fd = -1;
         assert(path);
 
-        /* Under the assumption that we are running privileged we
-         * first change the access mode and only then hand out
+        /* Under the assumption that we are running privileged we first change the access mode and only then hand out
          * ownership to avoid a window where access is too open. */
 
-        if (mode != MODE_INVALID)
-                if (chmod(path, mode) < 0)
+        fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change mode/owner
+                                                       * on the same file */
+        if (fd < 0)
+                return -errno;
+
+        xsprintf(fd_path, "/proc/self/fd/%i", fd);
+
+        if (mode != MODE_INVALID) {
+
+                if ((mode & S_IFMT) != 0) {
+                        struct stat st;
+
+                        if (stat(fd_path, &st) < 0)
+                                return -errno;
+
+                        if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
+                                return -EINVAL;
+                }
+
+                if (chmod(fd_path, mode & 07777) < 0)
                         return -errno;
+        }
 
         if (uid != UID_INVALID || gid != GID_INVALID)
-                if (chown(path, uid, gid) < 0)
+                if (chown(fd_path, uid, gid) < 0)
                         return -errno;
 
         return 0;
 }
 
 int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
-        /* Under the assumption that we are running privileged we
-         * first change the access mode and only then hand out
+        /* Under the assumption that we are running privileged we first change the access mode and only then hand out
          * ownership to avoid a window where access is too open. */
 
-        if (mode != MODE_INVALID)
-                if (fchmod(fd, mode) < 0)
+        if (mode != MODE_INVALID) {
+
+                if ((mode & S_IFMT) != 0) {
+                        struct stat st;
+
+                        if (fstat(fd, &st) < 0)
+                                return -errno;
+
+                        if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
+                                return -EINVAL;
+                }
+
+                if (fchmod(fd, mode & 0777) < 0)
                         return -errno;
+        }
 
         if (uid != UID_INVALID || gid != GID_INVALID)
                 if (fchown(fd, uid, gid) < 0)
@@ -264,7 +295,6 @@ int fchmod_opath(int fd, mode_t m) {
          * fchownat() does. */
 
         xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-
         if (chmod(procfs_path, m) < 0)
                 return -errno;
 
index 39e2dad5e7ab205ecec469df53677243e87f4b09..5bf244c49d1f58dc04fbae2012c6bb77f806ec74 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 set -eu
 
-$1 -E -dM -include sys/socket.h - </dev/null | \
+$1 -E -dM -include sys/socket.h -include "$2" -include "$3" - </dev/null | \
         grep -Ev 'AF_UNSPEC|AF_MAX' | \
         awk '/^#define[ \t]+AF_[^ \t]+[ \t]+[AP]F_[^ \t]/ { print $2; }'
index e4e7271c4de01add7153f75ad1fbbaaa756df292..e6e874a8fd06d0b4c83a0a4f50aef3960936c1c6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 set -eu
 
-$1 -dM -include net/if_arp.h - </dev/null | \
+$1 -dM -include net/if_arp.h -include "$2" -include "$3" - </dev/null | \
         awk '/^#define[ \t]+ARPHRD_[^ \t]+[ \t]+[^ \t]/ { print $2; }' | \
         sed -e 's/ARPHRD_//'
index 6f6832d23734ecb8a279ab81e262553ac5c2bd6b..d6dc34e60c976f3da05a83879eeb7210c23df0e9 100644 (file)
@@ -5,21 +5,13 @@
 #include "hash-funcs.h"
 #include "path-util.h"
 
-void string_hash_func(const void *p, struct siphash *state) {
+void string_hash_func(const char *p, struct siphash *state) {
         siphash24_compress(p, strlen(p) + 1, state);
 }
 
-int string_compare_func(const void *a, const void *b) {
-        return strcmp(a, b);
-}
-
-const struct hash_ops string_hash_ops = {
-        .hash = string_hash_func,
-        .compare = string_compare_func
-};
+DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
 
-void path_hash_func(const void *p, struct siphash *state) {
-        const char *q = p;
+void path_hash_func(const char *q, struct siphash *state) {
         size_t n;
 
         assert(q);
@@ -57,14 +49,11 @@ void path_hash_func(const void *p, struct siphash *state) {
         }
 }
 
-int path_compare_func(const void *a, const void *b) {
+int path_compare_func(const char *a, const char *b) {
         return path_compare(a, b);
 }
 
-const struct hash_ops path_hash_ops = {
-        .hash = path_hash_func,
-        .compare = path_compare_func
-};
+DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare_func);
 
 void trivial_hash_func(const void *p, struct siphash *state) {
         siphash24_compress(&p, sizeof(p), state);
@@ -79,36 +68,24 @@ const struct hash_ops trivial_hash_ops = {
         .compare = trivial_compare_func
 };
 
-void uint64_hash_func(const void *p, struct siphash *state) {
+void uint64_hash_func(const uint64_t *p, struct siphash *state) {
         siphash24_compress(p, sizeof(uint64_t), state);
 }
 
-int uint64_compare_func(const void *_a, const void *_b) {
-        uint64_t a, b;
-        a = *(const uint64_t*) _a;
-        b = *(const uint64_t*) _b;
-        return CMP(a, b);
+int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
+        return CMP(*a, *b);
 }
 
-const struct hash_ops uint64_hash_ops = {
-        .hash = uint64_hash_func,
-        .compare = uint64_compare_func
-};
+DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func);
 
 #if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) {
+void devt_hash_func(const dev_t *p, struct siphash *state) {
         siphash24_compress(p, sizeof(dev_t), state);
 }
 
-int devt_compare_func(const void *_a, const void *_b) {
-        dev_t a, b;
-        a = *(const dev_t*) _a;
-        b = *(const dev_t*) _b;
-        return CMP(a, b);
+int devt_compare_func(const dev_t *a, const dev_t *b) {
+        return CMP(*a, *b);
 }
 
-const struct hash_ops devt_hash_ops = {
-        .hash = devt_hash_func,
-        .compare = devt_compare_func
-};
+DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
 #endif
index fa45cfe256d5fc7374493fe8ab2cca909546a88c..3d2ae4b55ee99bef7337981c5d681c0c65100c6a 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "alloc-util.h"
 #include "macro.h"
 #include "siphash24.h"
 
@@ -10,14 +11,74 @@ typedef int (*compare_func_t)(const void *a, const void *b);
 struct hash_ops {
         hash_func_t hash;
         compare_func_t compare;
+        free_func_t free_key;
+        free_func_t free_value;
 };
 
-void string_hash_func(const void *p, struct siphash *state);
-int string_compare_func(const void *a, const void *b) _pure_;
+#define _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, free_key_func, free_value_func, scope) \
+        _unused_ static void (* UNIQ_T(static_hash_wrapper, uq))(const type *, struct siphash *) = hash_func; \
+        _unused_ static int (* UNIQ_T(static_compare_wrapper, uq))(const type *, const type *) = compare_func; \
+        scope const struct hash_ops name = {                            \
+                .hash = (hash_func_t) hash_func,                        \
+                .compare = (compare_func_t) compare_func,               \
+                .free_key = free_key_func,                              \
+                .free_value = free_value_func,                          \
+        }
+
+#define _DEFINE_FREE_FUNC(uq, type, wrapper_name, func)                 \
+        /* Type-safe free function */                                   \
+        static void UNIQ_T(wrapper_name, uq)(void *a) {                 \
+                type *_a = a;                                           \
+                func(_a);                                               \
+        }
+
+#define _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(uq, name, type, hash_func, compare_func, free_func, scope) \
+        _DEFINE_FREE_FUNC(uq, type, static_free_wrapper, free_func);    \
+        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
+                         UNIQ_T(static_free_wrapper, uq), NULL, scope)
+
+#define _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(uq, name, type, hash_func, compare_func, type_value, free_func, scope) \
+        _DEFINE_FREE_FUNC(uq, type_value, static_free_wrapper, free_func); \
+        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
+                         NULL, UNIQ_T(static_free_wrapper, uq), scope)
+
+#define _DEFINE_HASH_OPS_FULL(uq, name, type, hash_func, compare_func, free_key_func, type_value, free_value_func, scope) \
+        _DEFINE_FREE_FUNC(uq, type, static_free_key_wrapper, free_key_func); \
+        _DEFINE_FREE_FUNC(uq, type_value, static_free_value_wrapper, free_value_func); \
+        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
+                         UNIQ_T(static_free_key_wrapper, uq),           \
+                         UNIQ_T(static_free_value_wrapper, uq), scope)
+
+#define DEFINE_HASH_OPS(name, type, hash_func, compare_func)            \
+        _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL,)
+
+#define DEFINE_PRIVATE_HASH_OPS(name, type, hash_func, compare_func)    \
+        _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL, static)
+
+#define DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
+        _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
+        _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func, static)
+
+#define DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
+        _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
+        _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func, static)
+
+#define DEFINE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
+        _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
+        _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func, static)
+
+void string_hash_func(const char *p, struct siphash *state);
+#define string_compare_func strcmp
 extern const struct hash_ops string_hash_ops;
 
-void path_hash_func(const void *p, struct siphash *state);
-int path_compare_func(const void *a, const void *b) _pure_;
+void path_hash_func(const char *p, struct siphash *state);
+int path_compare_func(const char *a, const char *b) _pure_;
 extern const struct hash_ops path_hash_ops;
 
 /* This will compare the passed pointers directly, and will not dereference them. This is hence not useful for strings
@@ -28,15 +89,15 @@ extern const struct hash_ops trivial_hash_ops;
 
 /* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
  * values indirectly, since they don't fit in a pointer. */
-void uint64_hash_func(const void *p, struct siphash *state);
-int uint64_compare_func(const void *a, const void *b) _pure_;
+void uint64_hash_func(const uint64_t *p, struct siphash *state);
+int uint64_compare_func(const uint64_t *a, const uint64_t *b) _pure_;
 extern const struct hash_ops uint64_hash_ops;
 
 /* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on
  * 64bit archs. Yuck! */
 #if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) _pure_;
-int devt_compare_func(const void *a, const void *b) _pure_;
+void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
+int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
 extern const struct hash_ops devt_hash_ops;
 #else
 #define devt_hash_func uint64_hash_func
index eba56add1fc76a3e013f160a61609031c4006b1d..d0bdbe3d1b54f85d68ab85a170b4baec62b992b9 100644 (file)
@@ -276,7 +276,7 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
 };
 
 #if VALGRIND
-__attribute__((destructor)) static void cleanup_pools(void) {
+_destructor_ static void cleanup_pools(void) {
         _cleanup_free_ char *t = NULL;
         int r;
 
@@ -848,7 +848,7 @@ int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops  HASH
 
 static void hashmap_free_no_clear(HashmapBase *h) {
         assert(!h->has_indirect);
-        assert(!h->n_direct_entries);
+        assert(h->n_direct_entries == 0);
 
 #if ENABLE_DEBUG_HASHMAP
         assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
@@ -864,47 +864,38 @@ static void hashmap_free_no_clear(HashmapBase *h) {
                 free(h);
 }
 
-HashmapBase *internal_hashmap_free(HashmapBase *h) {
-
-        /* Free the hashmap, but nothing in it */
-
+HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
         if (h) {
-                internal_hashmap_clear(h);
+                internal_hashmap_clear(h, default_free_key, default_free_value);
                 hashmap_free_no_clear(h);
         }
 
         return NULL;
 }
 
-HashmapBase *internal_hashmap_free_free(HashmapBase *h) {
+void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+        free_func_t free_key, free_value;
+        if (!h)
+                return;
 
-        /* Free the hashmap and all data objects in it, but not the
-         * keys */
+        free_key = h->hash_ops->free_key ?: default_free_key;
+        free_value = h->hash_ops->free_value ?: default_free_value;
 
-        if (h) {
-                internal_hashmap_clear_free(h);
-                hashmap_free_no_clear(h);
-        }
-
-        return NULL;
-}
+        if (free_key || free_value) {
+                unsigned idx;
 
-Hashmap *hashmap_free_free_free(Hashmap *h) {
+                for (idx = skip_free_buckets(h, 0); idx != IDX_NIL;
+                     idx = skip_free_buckets(h, idx + 1)) {
+                        struct hashmap_base_entry *e = bucket_at(h, idx);
 
-        /* Free the hashmap and all data and key objects in it */
+                        if (free_key)
+                                free_key((void *) e->key);
 
-        if (h) {
-                hashmap_clear_free_free(h);
-                hashmap_free_no_clear(HASHMAP_BASE(h));
+                        if (free_value)
+                                free_value(entry_value(h, e));
+                }
         }
 
-        return NULL;
-}
-
-void internal_hashmap_clear(HashmapBase *h) {
-        if (!h)
-                return;
-
         if (h->has_indirect) {
                 free(h->indirect.storage);
                 h->has_indirect = false;
@@ -921,35 +912,6 @@ void internal_hashmap_clear(HashmapBase *h) {
         base_set_dirty(h);
 }
 
-void internal_hashmap_clear_free(HashmapBase *h) {
-        unsigned idx;
-
-        if (!h)
-                return;
-
-        for (idx = skip_free_buckets(h, 0); idx != IDX_NIL;
-             idx = skip_free_buckets(h, idx + 1))
-                free(entry_value(h, bucket_at(h, idx)));
-
-        internal_hashmap_clear(h);
-}
-
-void hashmap_clear_free_free(Hashmap *h) {
-        unsigned idx;
-
-        if (!h)
-                return;
-
-        for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL;
-             idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) {
-                struct plain_hashmap_entry *e = plain_bucket_at(h, idx);
-                free((void*)e->b.key);
-                free(e->value);
-        }
-
-        internal_hashmap_clear(HASHMAP_BASE(h));
-}
-
 static int resize_buckets(HashmapBase *h, unsigned entries_add);
 
 /*
@@ -1740,7 +1702,7 @@ HashmapBase *internal_hashmap_copy(HashmapBase *h) {
         }
 
         if (r < 0) {
-                internal_hashmap_free(copy);
+                internal_hashmap_free(copy, false, false);
                 return NULL;
         }
 
index bb2a5c76ec3e60a6e63bba282f333556a298d77d..a330a1d4946eb0ff2d4906648801444ca6617aaa 100644 (file)
@@ -22,6 +22,8 @@
 
 #define HASH_KEY_SIZE 16
 
+typedef void* (*hashmap_destroy_t)(void *p);
+
 /* The base type for all hashmap and set types. Many functions in the
  * implementation take (HashmapBase*) parameters and are run-time polymorphic,
  * though the API is not meant to be polymorphic (do not call functions
@@ -87,25 +89,33 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops  HA
 #define hashmap_new(ops) internal_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
 #define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
 
-HashmapBase *internal_hashmap_free(HashmapBase *h);
+HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
 static inline Hashmap *hashmap_free(Hashmap *h) {
-        return (void*)internal_hashmap_free(HASHMAP_BASE(h));
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
 }
 static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
-        return (void*)internal_hashmap_free(HASHMAP_BASE(h));
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
 }
 
-HashmapBase *internal_hashmap_free_free(HashmapBase *h);
 static inline Hashmap *hashmap_free_free(Hashmap *h) {
-        return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
 }
 static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
-        return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
 }
 
-Hashmap *hashmap_free_free_free(Hashmap *h);
+static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+}
+static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+}
+
+static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+}
 static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
-        return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
+        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
 }
 
 IteratedCache *iterated_cache_free(IteratedCache *cache);
@@ -258,25 +268,33 @@ static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void
         return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
 }
 
-void internal_hashmap_clear(HashmapBase *h);
+void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
 static inline void hashmap_clear(Hashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h));
+        internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
 }
 static inline void ordered_hashmap_clear(OrderedHashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h));
+        internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
 }
 
-void internal_hashmap_clear_free(HashmapBase *h);
 static inline void hashmap_clear_free(Hashmap *h) {
-        internal_hashmap_clear_free(HASHMAP_BASE(h));
+        internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
 }
 static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
-        internal_hashmap_clear_free(HASHMAP_BASE(h));
+        internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
 }
 
-void hashmap_clear_free_free(Hashmap *h);
+static inline void hashmap_clear_free_key(Hashmap *h) {
+        internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+}
+static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
+        internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+}
+
+static inline void hashmap_clear_free_free(Hashmap *h) {
+        internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+}
 static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
-        hashmap_clear_free_free(PLAIN_HASHMAP(h));
+        internal_hashmap_clear(HASHMAP_BASE(h), free, free);
 }
 
 /*
index 3a3479910d77a8bc047bdf7c0a34b6cc1bf85f20..5bfa028b39306b48a2482fd51d6217a77eafe063 100644 (file)
@@ -69,12 +69,12 @@ int gethostname_strict(char **ret) {
         return 0;
 }
 
-static bool hostname_valid_char(char c) {
+bool valid_ldh_char(char c) {
         return
                 (c >= 'a' && c <= 'z') ||
                 (c >= 'A' && c <= 'Z') ||
                 (c >= '0' && c <= '9') ||
-                IN_SET(c, '-', '_', '.');
+                c == '-';
 }
 
 /**
@@ -90,7 +90,7 @@ static bool hostname_valid_char(char c) {
 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
         unsigned n_dots = 0;
         const char *p;
-        bool dot;
+        bool dot, hyphen;
 
         if (isempty(s))
                 return false;
@@ -100,23 +100,34 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
          * sequence. Also ensures that the length stays below
          * HOST_NAME_MAX. */
 
-        for (p = s, dot = true; *p; p++) {
+        for (p = s, dot = hyphen = true; *p; p++)
                 if (*p == '.') {
-                        if (dot)
+                        if (dot || hyphen)
                                 return false;
 
                         dot = true;
+                        hyphen = false;
                         n_dots++;
+
+                } else if (*p == '-') {
+                        if (dot)
+                                return false;
+
+                        dot = false;
+                        hyphen = true;
+
                 } else {
-                        if (!hostname_valid_char(*p))
+                        if (!valid_ldh_char(*p))
                                 return false;
 
                         dot = false;
+                        hyphen = false;
                 }
-        }
 
         if (dot && (n_dots < 2 || !allow_trailing_dot))
                 return false;
+        if (hyphen)
+                return false;
 
         if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
                                   * Linux, but DNS allows domain names
@@ -128,29 +139,38 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
 
 char* hostname_cleanup(char *s) {
         char *p, *d;
-        bool dot;
+        bool dot, hyphen;
 
         assert(s);
 
-        strshorten(s, HOST_NAME_MAX);
-
-        for (p = s, d = s, dot = true; *p; p++) {
+        for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
                 if (*p == '.') {
-                        if (dot)
+                        if (dot || hyphen)
                                 continue;
 
                         *(d++) = '.';
                         dot = true;
-                } else if (hostname_valid_char(*p)) {
+                        hyphen = false;
+
+                } else if (*p == '-') {
+                        if (dot)
+                                continue;
+
+                        *(d++) = '-';
+                        dot = false;
+                        hyphen = true;
+
+                } else if (valid_ldh_char(*p)) {
                         *(d++) = *p;
                         dot = false;
+                        hyphen = false;
                 }
-        }
 
-        if (dot && d > s)
-                d[-1] = 0;
-        else
-                *d = 0;
+        if (d > s && IN_SET(d[-1], '-', '.'))
+                /* The dot can occur at most once, but we might have multiple
+                 * hyphens, hence the loop */
+                d--;
+        *d = 0;
 
         return s;
 }
index 749481723de3d83dd2fc8a092ff8468e083d8fd2..7ba386a0fd99c5162cd32b22e63b8ce24e344532 100644 (file)
@@ -11,6 +11,7 @@ bool hostname_is_set(void);
 char* gethostname_malloc(void);
 int gethostname_strict(char **ret);
 
+bool valid_ldh_char(char c) _const_;
 bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
 char* hostname_cleanup(char *s);
 
index 6a00de2ef09126d2cdfd3042344d590338c2bf54..4bb7d9c5e0a6858be21a869ba5b387609f4318c3 100644 (file)
@@ -603,15 +603,12 @@ int in_addr_prefix_from_string_auto_internal(
 
 }
 
-void in_addr_data_hash_func(const void *p, struct siphash *state) {
-        const struct in_addr_data *a = p;
-
+static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
         siphash24_compress(&a->family, sizeof(a->family), state);
         siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
 }
 
-int in_addr_data_compare_func(const void *a, const void *b) {
-        const struct in_addr_data *x = a, *y = b;
+static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
         int r;
 
         r = CMP(x->family, y->family);
@@ -621,7 +618,4 @@ int in_addr_data_compare_func(const void *a, const void *b) {
         return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
 }
 
-const struct hash_ops in_addr_data_hash_ops = {
-        .hash = in_addr_data_hash_func,
-        .compare = in_addr_data_compare_func,
-};
+DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
index 2f64c31f96b1ccb7c92452c70ecbbf21759d03e0..5de85cc422084dc33fa583d878a14532fce16ee8 100644 (file)
@@ -69,6 +69,4 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
  * See also oss-fuzz#11344. */
 #define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
 
-void in_addr_data_hash_func(const void *p, struct siphash *state);
-int in_addr_data_compare_func(const void *a, const void *b);
 extern const struct hash_ops in_addr_data_hash_ops;
index b2ef66392e118340db7c62c78d4f5c649c4302f2..cf4d22fbce45644c1be3b7edba120b1ff0842f37 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "def.h"
 #include "dirent-util.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "hashmap.h"
 #include "locale-util.h"
@@ -347,6 +348,24 @@ bool keymap_is_valid(const char *name) {
         return true;
 }
 
+static bool emoji_enabled(void) {
+        static int cached_emoji_enabled = -1;
+
+        if (cached_emoji_enabled < 0) {
+                int val;
+
+                val = getenv_bool("SYSTEMD_EMOJI");
+                if (val < 0)
+                        cached_emoji_enabled =
+                                is_locale_utf8() &&
+                                !STRPTR_IN_SET(getenv("TERM"), "dumb", "linux");
+                else
+                        cached_emoji_enabled = val;
+        }
+
+        return cached_emoji_enabled;
+}
+
 const char *special_glyph(SpecialGlyph code) {
 
         /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be
@@ -359,43 +378,59 @@ const char *special_glyph(SpecialGlyph code) {
         static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = {
                 /* ASCII fallback */
                 [false] = {
-                        [TREE_VERTICAL]      = "| ",
-                        [TREE_BRANCH]        = "|-",
-                        [TREE_RIGHT]         = "`-",
-                        [TREE_SPACE]         = "  ",
-                        [TRIANGULAR_BULLET]  = ">",
-                        [BLACK_CIRCLE]       = "*",
-                        [BULLET]             = "*",
-                        [ARROW]              = "->",
-                        [MDASH]              = "-",
-                        [ELLIPSIS]           = "...",
-                        [MU]                 = "u",
-                        [CHECK_MARK]         = "+",
-                        [CROSS_MARK]         = "-",
+                        [TREE_VERTICAL]           = "| ",
+                        [TREE_BRANCH]             = "|-",
+                        [TREE_RIGHT]              = "`-",
+                        [TREE_SPACE]              = "  ",
+                        [TRIANGULAR_BULLET]       = ">",
+                        [BLACK_CIRCLE]            = "*",
+                        [BULLET]                  = "*",
+                        [ARROW]                   = "->",
+                        [MDASH]                   = "-",
+                        [ELLIPSIS]                = "...",
+                        [MU]                      = "u",
+                        [CHECK_MARK]              = "+",
+                        [CROSS_MARK]              = "-",
+                        [ECSTATIC_SMILEY]         = ":-]",
+                        [HAPPY_SMILEY]            = ":-}",
+                        [SLIGHTLY_HAPPY_SMILEY]   = ":-)",
+                        [NEUTRAL_SMILEY]          = ":-|",
+                        [SLIGHTLY_UNHAPPY_SMILEY] = ":-(",
+                        [UNHAPPY_SMILEY]          = ":-{️",
+                        [DEPRESSED_SMILEY]        = ":-[",
                 },
 
                 /* UTF-8 */
                 [true] = {
-                        [TREE_VERTICAL]      = "\342\224\202 ",            /* │  */
-                        [TREE_BRANCH]        = "\342\224\234\342\224\200", /* ├─ */
-                        [TREE_RIGHT]         = "\342\224\224\342\224\200", /* └─ */
-                        [TREE_SPACE]         = "  ",                       /*    */
-                        [TRIANGULAR_BULLET]  = "\342\200\243",             /* ‣ */
-                        [BLACK_CIRCLE]       = "\342\227\217",             /* ● */
-                        [BULLET]             = "\342\200\242",             /* • */
-                        [ARROW]              = "\342\206\222",             /* → */
-                        [MDASH]              = "\342\200\223",             /* – */
-                        [ELLIPSIS]           = "\342\200\246",             /* … */
-                        [MU]                 = "\316\274",                 /* μ */
-                        [CHECK_MARK]         = "\342\234\223",             /* ✓ */
-                        [CROSS_MARK]         = "\342\234\227",             /* ✗ */
+                        [TREE_VERTICAL]           = "\342\224\202 ",            /* │  */
+                        [TREE_BRANCH]             = "\342\224\234\342\224\200", /* ├─ */
+                        [TREE_RIGHT]              = "\342\224\224\342\224\200", /* └─ */
+                        [TREE_SPACE]              = "  ",                       /*    */
+                        [TRIANGULAR_BULLET]       = "\342\200\243",             /* ‣ */
+                        [BLACK_CIRCLE]            = "\342\227\217",             /* ● */
+                        [BULLET]                  = "\342\200\242",             /* • */
+                        [ARROW]                   = "\342\206\222",             /* → */
+                        [MDASH]                   = "\342\200\223",             /* – */
+                        [ELLIPSIS]                = "\342\200\246",             /* … */
+                        [MU]                      = "\316\274",                 /* μ */
+                        [CHECK_MARK]              = "\342\234\223",             /* ✓ */
+                        [CROSS_MARK]              = "\342\234\227",             /* ✗ */
+                        [ECSTATIC_SMILEY]         = "\360\237\230\207",         /* 😇 */
+                        [HAPPY_SMILEY]            = "\360\237\230\200",         /* 😀 */
+                        [SLIGHTLY_HAPPY_SMILEY]   = "\360\237\231\202",         /* 🙂 */
+                        [NEUTRAL_SMILEY]          = "\360\237\230\220",         /* 😐 */
+                        [SLIGHTLY_UNHAPPY_SMILEY] = "\360\237\231\201",         /* 🙁 */
+                        [UNHAPPY_SMILEY]          = "\360\237\230\250",         /* 😨️️ */
+                        [DEPRESSED_SMILEY]        = "\360\237\244\242",         /* 🤢 */
                 },
         };
 
-        return draw_table[is_locale_utf8()][code];
+        assert(code < _SPECIAL_GLYPH_MAX);
+
+        return draw_table[code >= _SPECIAL_GLYPH_FIRST_SMILEY ? emoji_enabled() : is_locale_utf8()][code];
 }
 
-void locale_variables_free(char*l[_VARIABLE_LC_MAX]) {
+void locale_variables_free(char *l[_VARIABLE_LC_MAX]) {
         LocaleVariable i;
 
         if (!l)
index 2aa2bef8c5cbb72005f214340ad75e3ebed4f0e5..8f4ce5485d90b73845c5a3affce22f855bf1b899 100644 (file)
@@ -52,6 +52,14 @@ typedef enum {
         MU,
         CHECK_MARK,
         CROSS_MARK,
+        _SPECIAL_GLYPH_FIRST_SMILEY,
+        ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_SMILEY,
+        HAPPY_SMILEY,
+        SLIGHTLY_HAPPY_SMILEY,
+        NEUTRAL_SMILEY,
+        SLIGHTLY_UNHAPPY_SMILEY,
+        UNHAPPY_SMILEY,
+        DEPRESSED_SMILEY,
         _SPECIAL_GLYPH_MAX
 } SpecialGlyph;
 
index 0a258cc614a146a99b23ba7baa64a65d518f0328..1971e912db4f497e676af561733f98286397e4ad 100644 (file)
@@ -2,33 +2,38 @@
 #pragma once
 
 #include <assert.h>
+#include <errno.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <sys/param.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 
-#define _printf_(a, b) __attribute__ ((__format__(printf, a, b)))
+#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
 #ifdef __clang__
 #  define _alloc_(...)
 #else
-#  define _alloc_(...) __attribute__ ((__alloc_size__(__VA_ARGS__)))
+#  define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
 #endif
-#define _sentinel_ __attribute__ ((__sentinel__))
-#define _unused_ __attribute__ ((__unused__))
-#define _destructor_ __attribute__ ((__destructor__))
-#define _pure_ __attribute__ ((__pure__))
-#define _const_ __attribute__ ((__const__))
-#define _deprecated_ __attribute__ ((__deprecated__))
-#define _packed_ __attribute__ ((__packed__))
-#define _malloc_ __attribute__ ((__malloc__))
-#define _weak_ __attribute__ ((__weak__))
+#define _sentinel_ __attribute__((__sentinel__))
+#define _section_(x) __attribute__((__section__(x)))
+#define _used_ __attribute__((__used__))
+#define _unused_ __attribute__((__unused__))
+#define _destructor_ __attribute__((__destructor__))
+#define _pure_ __attribute__((__pure__))
+#define _const_ __attribute__((__const__))
+#define _deprecated_ __attribute__((__deprecated__))
+#define _packed_ __attribute__((__packed__))
+#define _malloc_ __attribute__((__malloc__))
+#define _weak_ __attribute__((__weak__))
 #define _likely_(x) (__builtin_expect(!!(x), 1))
 #define _unlikely_(x) (__builtin_expect(!!(x), 0))
-#define _public_ __attribute__ ((__visibility__("default")))
-#define _hidden_ __attribute__ ((__visibility__("hidden")))
+#define _public_ __attribute__((__visibility__("default")))
+#define _hidden_ __attribute__((__visibility__("hidden")))
 #define _weakref_(x) __attribute__((__weakref__(#x)))
+#define _align_(x) __attribute__((__aligned__(x)))
 #define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
+#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
 #define _cleanup_(x) __attribute__((__cleanup__(x)))
 #if __GNUC__ >= 7
 #define _fallthrough_ __attribute__((__fallthrough__))
 #  endif
 #endif
 
+#if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
+#  ifdef __SANITIZE_ADDRESS__
+#      define HAS_FEATURE_ADDRESS_SANITIZER 1
+#  elif defined(__has_feature)
+#    if __has_feature(address_sanitizer)
+#      define HAS_FEATURE_ADDRESS_SANITIZER 1
+#    endif
+#  endif
+#  if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
+#    define HAS_FEATURE_ADDRESS_SANITIZER 0
+#  endif
+#endif
+
+/* Note: on GCC "no_sanitize_address" is a function attribute only, on llvm it may also be applied to global
+ * variables. We define a specific macro which knows this. Note that on GCC we don't need this decorator so much, since
+ * our primary usecase for this attribute is registration structures placed in named ELF sections which shall not be
+ * padded, but GCC doesn't pad those anyway if AddressSanitizer is enabled. */
+#if HAS_FEATURE_ADDRESS_SANITIZER && defined(__clang__)
+#define _variable_no_sanitize_address_ __attribute__((__no_sanitize_address__))
+#else
+#define _variable_no_sanitize_address_
+#endif
+
 /* Temporarily disable some warnings */
 #define DISABLE_WARNING_FORMAT_NONLITERAL                               \
         _Pragma("GCC diagnostic push");                                 \
@@ -246,11 +274,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
  * computation should be possible in the given type. Therefore, we use
  * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
  * quotient and the remainder, so both should be equally fast. */
-#define DIV_ROUND_UP(_x, _y)                                            \
+#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
+#define __DIV_ROUND_UP(xq, x, yq, y)                                    \
         ({                                                              \
-                const typeof(_x) __x = (_x);                            \
-                const typeof(_y) __y = (_y);                            \
-                (__x / __y + !!(__x % __y));                            \
+                const typeof(x) UNIQ_T(X, xq) = (x);                    \
+                const typeof(y) UNIQ_T(Y, yq) = (y);                    \
+                (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
         })
 
 #ifdef __COVERITY__
@@ -457,6 +486,11 @@ static inline int __coverity_check__(int condition) {
 #endif
 #endif
 
+#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func)             \
+        static inline void name(type *p) {                      \
+                func(p);                                        \
+        }
+
 #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)                 \
         static inline void func##p(type *p) {                   \
                 if (*p)                                         \
index b13897f334a902de6ae2bca3a1513fbce2d773d8..23b5e75bd8ae3e56ebb175708e49cc2b499e7217 100644 (file)
@@ -17,7 +17,6 @@ basic_sources = files('''
         audit-util.h
         blockdev-util.c
         blockdev-util.h
-        btrfs-ctree.h
         btrfs-util.c
         btrfs-util.h
         build.h
@@ -40,6 +39,8 @@ basic_sources = files('''
         device-nodes.h
         dirent-util.c
         dirent-util.h
+        env-file.c
+        env-file.h
         env-util.c
         env-util.h
         errno-list.c
@@ -90,12 +91,42 @@ basic_sources = files('''
         memfd-util.h
         mempool.c
         mempool.h
+        missing.h
+        missing_audit.h
+        missing_btrfs.h
+        missing_btrfs_tree.h
+        missing_capability.h
+        missing_drm.h
+        missing_ethtool.h
+        missing_fcntl.h
+        missing_fib_rules.h
+        missing_fou.h
+        missing_fs.h
+        missing_if_bridge.h
+        missing_if_link.h
+        missing_if_tunnel.h
+        missing_input.h
+        missing_keyctl.h
+        missing_magic.h
+        missing_mman.h
+        missing_network.h
+        missing_prctl.h
+        missing_random.h
+        missing_resource.h
+        missing_sched.h
+        missing_securebits.h
+        missing_socket.h
+        missing_stat.h
+        missing_stdlib.h
         missing_syscall.h
+        missing_timerfd.h
+        missing_type.h
+        missing_vxcan.h
         mkdir-label.c
         mkdir.c
         mkdir.h
-        mount-util.c
-        mount-util.h
+        mountpoint-util.c
+        mountpoint-util.h
         nss-util.h
         ordered-set.c
         ordered-set.h
@@ -120,9 +151,10 @@ basic_sources = files('''
         refcnt.h
         replace-var.c
         replace-var.h
+        rlimit-util.c
+        rlimit-util.h
         rm-rf.c
         rm-rf.h
-        securebits.h
         selinux-util.c
         selinux-util.h
         set.h
@@ -159,6 +191,8 @@ basic_sources = files('''
         terminal-util.h
         time-util.c
         time-util.h
+        tmpfile-util.c
+        tmpfile-util.h
         umask-util.h
         unaligned.h
         unit-def.c
@@ -177,27 +211,30 @@ basic_sources = files('''
         xattr-util.h
 '''.split())
 
-missing_h = files('missing.h')
+missing_audit_h = files('missing_audit.h')
+missing_capability_h = files('missing_capability.h')
+missing_network_h = files('missing_network.h')
+missing_socket_h = files('missing_socket.h')
 
 generate_af_list = find_program('generate-af-list.sh')
 af_list_txt = custom_target(
         'af-list.txt',
         output : 'af-list.txt',
-        command : [generate_af_list, cpp],
+        command : [generate_af_list, cpp, config_h, missing_socket_h],
         capture : true)
 
 generate_arphrd_list = find_program('generate-arphrd-list.sh')
 arphrd_list_txt = custom_target(
         'arphrd-list.txt',
         output : 'arphrd-list.txt',
-        command : [generate_arphrd_list, cpp],
+        command : [generate_arphrd_list, cpp, config_h, missing_network_h],
         capture : true)
 
 generate_cap_list = find_program('generate-cap-list.sh')
 cap_list_txt = custom_target(
         'cap-list.txt',
         output : 'cap-list.txt',
-        command : [generate_cap_list, cpp, config_h, missing_h],
+        command : [generate_cap_list, cpp, config_h, missing_capability_h],
         capture : true)
 
 generate_errno_list = find_program('generate-errno-list.sh')
@@ -246,7 +283,7 @@ foreach item : [['af',     af_list_txt,     'af',         ''],
         generated_gperf_headers += [target1, target2]
 endforeach
 
-basic_sources += [missing_h] + generated_gperf_headers
+basic_sources += generated_gperf_headers
 basic_gcrypt_sources = files(
         'gcrypt-util.c',
         'gcrypt-util.h')
@@ -257,7 +294,6 @@ libbasic = static_library(
         include_directories : includes,
         dependencies : [threads,
                         libcap,
-                        libmount,
                         libselinux,
                         libm],
         c_args : ['-fvisibility=default'],
index 99a463b7b6e305edd680f8c4534c3fc12f785825..5067c8fd009a80bc426e494c57da523eb79d96bd 100644 (file)
 
 /* Missing glibc definitions to access certain kernel APIs */
 
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/audit.h>
-#include <linux/capability.h>
-#include <linux/falloc.h>
-#include <linux/fib_rules.h>
-#include <linux/if_link.h>
-#include <linux/input.h>
-#include <linux/loop.h>
-#include <linux/neighbour.h>
-#include <linux/oom.h>
-#include <linux/rtnetlink.h>
-#include <net/ethernet.h>
-#include <stdlib.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <uchar.h>
-#include <unistd.h>
-
-#if WANT_LINUX_STAT_H
-#include <linux/stat.h>
-#endif
-
-#if HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#ifdef ARCH_MIPS
-#include <asm/sgidefs.h>
-#endif
-
-#if HAVE_LINUX_BTRFS_H
-#include <linux/btrfs.h>
-#endif
-
-#if HAVE_LINUX_VM_SOCKETS_H
-#include <linux/vm_sockets.h>
-#else
-#define VMADDR_CID_ANY -1U
-struct sockaddr_vm {
-        unsigned short svm_family;
-        unsigned short svm_reserved1;
-        unsigned int svm_port;
-        unsigned int svm_cid;
-        unsigned char svm_zero[sizeof(struct sockaddr) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned int) -
-                               sizeof(unsigned int)];
-};
-#endif /* !HAVE_LINUX_VM_SOCKETS_H */
-
-#ifndef RLIMIT_RTTIME
-#define RLIMIT_RTTIME 15
-#endif
-
-/* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */
-#define _RLIMIT_MAX (RLIMIT_RTTIME+1 > RLIMIT_NLIMITS ? RLIMIT_RTTIME+1 : RLIMIT_NLIMITS)
-
-#ifndef F_LINUX_SPECIFIC_BASE
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif
-
-#ifndef F_SETPIPE_SZ
-#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
-#endif
-
-#ifndef F_GETPIPE_SZ
-#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
-#endif
-
-#ifndef F_ADD_SEALS
-#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
-#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
-
-#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
-#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
-#define F_SEAL_GROW     0x0004  /* prevent file from growing */
-#define F_SEAL_WRITE    0x0008  /* prevent writes */
-#endif
-
-#ifndef F_OFD_GETLK
-#define F_OFD_GETLK     36
-#define F_OFD_SETLK     37
-#define F_OFD_SETLKW    38
-#endif
-
-#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
-#endif
-
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#endif
-
-#ifndef IP_FREEBIND
-#define IP_FREEBIND 15
-#endif
-
-#ifndef OOM_SCORE_ADJ_MIN
-#define OOM_SCORE_ADJ_MIN (-1000)
-#endif
-
-#ifndef OOM_SCORE_ADJ_MAX
-#define OOM_SCORE_ADJ_MAX 1000
-#endif
-
-#ifndef AUDIT_SERVICE_START
-#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
-#endif
-
-#ifndef AUDIT_SERVICE_STOP
-#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
-#endif
-
-#ifndef TIOCVHANGUP
-#define TIOCVHANGUP 0x5437
-#endif
-
-#ifndef IP_TRANSPARENT
-#define IP_TRANSPARENT 19
-#endif
-
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-#ifndef NETLINK_LIST_MEMBERSHIPS
-#define NETLINK_LIST_MEMBERSHIPS 9
-#endif
-
-#ifndef SOL_SCTP
-#define SOL_SCTP 132
-#endif
-
-#ifndef GRND_NONBLOCK
-#define GRND_NONBLOCK 0x0001
-#endif
-
-#ifndef GRND_RANDOM
-#define GRND_RANDOM 0x0002
-#endif
-
-#ifndef FS_NOCOW_FL
-#define FS_NOCOW_FL 0x00800000
-#endif
-
-#ifndef BTRFS_IOCTL_MAGIC
-#define BTRFS_IOCTL_MAGIC 0x94
-#endif
-
-#ifndef BTRFS_PATH_NAME_MAX
-#define BTRFS_PATH_NAME_MAX 4087
-#endif
-
-#ifndef BTRFS_DEVICE_PATH_NAME_MAX
-#define BTRFS_DEVICE_PATH_NAME_MAX 1024
-#endif
-
-#ifndef BTRFS_FSID_SIZE
-#define BTRFS_FSID_SIZE 16
-#endif
-
-#ifndef BTRFS_UUID_SIZE
-#define BTRFS_UUID_SIZE 16
-#endif
-
-#ifndef BTRFS_SUBVOL_RDONLY
-#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
-#endif
-
-#ifndef BTRFS_SUBVOL_NAME_MAX
-#define BTRFS_SUBVOL_NAME_MAX 4039
-#endif
-
-#ifndef BTRFS_INO_LOOKUP_PATH_MAX
-#define BTRFS_INO_LOOKUP_PATH_MAX 4080
-#endif
-
-#ifndef BTRFS_SEARCH_ARGS_BUFSIZE
-#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
-#endif
-
-#ifndef BTRFS_QGROUP_LEVEL_SHIFT
-#define BTRFS_QGROUP_LEVEL_SHIFT 48
-#endif
-
-#if ! HAVE_LINUX_BTRFS_H
-#define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \
-                               struct btrfs_ioctl_qgroup_assign_args)
-#define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \
-                               struct btrfs_ioctl_qgroup_create_args)
-#define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \
-                               struct btrfs_ioctl_quota_rescan_args)
-#define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \
-                               struct btrfs_ioctl_quota_rescan_args)
-
-struct btrfs_ioctl_quota_rescan_args {
-        __u64   flags;
-        __u64   progress;
-        __u64   reserved[6];
-};
-
-struct btrfs_ioctl_qgroup_assign_args {
-        __u64 assign;
-        __u64 src;
-        __u64 dst;
-};
-
-struct btrfs_ioctl_qgroup_create_args {
-        __u64 create;
-        __u64 qgroupid;
-};
-
-struct btrfs_ioctl_vol_args {
-        int64_t fd;
-        char name[BTRFS_PATH_NAME_MAX + 1];
-};
-
-struct btrfs_qgroup_limit {
-        __u64 flags;
-        __u64 max_rfer;
-        __u64 max_excl;
-        __u64 rsv_rfer;
-        __u64 rsv_excl;
-};
-
-struct btrfs_qgroup_inherit {
-        __u64 flags;
-        __u64 num_qgroups;
-        __u64 num_ref_copies;
-        __u64 num_excl_copies;
-        struct btrfs_qgroup_limit lim;
-        __u64 qgroups[0];
-};
-
-struct btrfs_ioctl_qgroup_limit_args {
-        __u64 qgroupid;
-        struct btrfs_qgroup_limit lim;
-};
-
-struct btrfs_ioctl_vol_args_v2 {
-        __s64 fd;
-        __u64 transid;
-        __u64 flags;
-        union {
-                struct {
-                        __u64 size;
-                        struct btrfs_qgroup_inherit *qgroup_inherit;
-                };
-                __u64 unused[4];
-        };
-        char name[BTRFS_SUBVOL_NAME_MAX + 1];
-};
-
-struct btrfs_ioctl_dev_info_args {
-        uint64_t devid;                         /* in/out */
-        uint8_t uuid[BTRFS_UUID_SIZE];          /* in/out */
-        uint64_t bytes_used;                    /* out */
-        uint64_t total_bytes;                   /* out */
-        uint64_t unused[379];                   /* pad to 4k */
-        char path[BTRFS_DEVICE_PATH_NAME_MAX];  /* out */
-};
-
-struct btrfs_ioctl_fs_info_args {
-        uint64_t max_id;                        /* out */
-        uint64_t num_devices;                   /* out */
-        uint8_t fsid[BTRFS_FSID_SIZE];          /* out */
-        uint64_t reserved[124];                 /* pad to 1k */
-};
-
-struct btrfs_ioctl_ino_lookup_args {
-        __u64 treeid;
-        __u64 objectid;
-        char name[BTRFS_INO_LOOKUP_PATH_MAX];
-};
-
-struct btrfs_ioctl_search_key {
-        /* which root are we searching.  0 is the tree of tree roots */
-        __u64 tree_id;
-
-        /* keys returned will be >= min and <= max */
-        __u64 min_objectid;
-        __u64 max_objectid;
-
-        /* keys returned will be >= min and <= max */
-        __u64 min_offset;
-        __u64 max_offset;
-
-        /* max and min transids to search for */
-        __u64 min_transid;
-        __u64 max_transid;
-
-        /* keys returned will be >= min and <= max */
-        __u32 min_type;
-        __u32 max_type;
-
-        /*
-         * how many items did userland ask for, and how many are we
-         * returning
-         */
-        __u32 nr_items;
-
-        /* align to 64 bits */
-        __u32 unused;
-
-        /* some extra for later */
-        __u64 unused1;
-        __u64 unused2;
-        __u64 unused3;
-        __u64 unused4;
-};
-
-struct btrfs_ioctl_search_header {
-        __u64 transid;
-        __u64 objectid;
-        __u64 offset;
-        __u32 type;
-        __u32 len;
-};
-
-struct btrfs_ioctl_search_args {
-        struct btrfs_ioctl_search_key key;
-        char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
-};
-
-struct btrfs_ioctl_clone_range_args {
-        __s64 src_fd;
-        __u64 src_offset, src_length;
-        __u64 dest_offset;
-};
-
-#define BTRFS_QUOTA_CTL_ENABLE  1
-#define BTRFS_QUOTA_CTL_DISABLE 2
-#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3
-struct btrfs_ioctl_quota_ctl_args {
-        __u64 cmd;
-        __u64 status;
-};
-#endif
-
-#ifndef BTRFS_IOC_DEFRAG
-#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
-                                 struct btrfs_ioctl_vol_args)
-#endif
-
-#ifndef BTRFS_IOC_RESIZE
-#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \
-                                 struct btrfs_ioctl_vol_args)
-#endif
-
-#ifndef BTRFS_IOC_CLONE
-#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int)
-#endif
-
-#ifndef BTRFS_IOC_CLONE_RANGE
-#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \
-                                 struct btrfs_ioctl_clone_range_args)
-#endif
-
-#ifndef BTRFS_IOC_SUBVOL_CREATE
-#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
-                                 struct btrfs_ioctl_vol_args)
-#endif
-
-#ifndef BTRFS_IOC_SNAP_DESTROY
-#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
-                                 struct btrfs_ioctl_vol_args)
-#endif
-
-#ifndef BTRFS_IOC_TREE_SEARCH
-#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
-                                 struct btrfs_ioctl_search_args)
-#endif
-
-#ifndef BTRFS_IOC_INO_LOOKUP
-#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
-                                 struct btrfs_ioctl_ino_lookup_args)
-#endif
-
-#ifndef BTRFS_IOC_SNAP_CREATE_V2
-#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
-                                 struct btrfs_ioctl_vol_args_v2)
-#endif
-
-#ifndef BTRFS_IOC_SUBVOL_GETFLAGS
-#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
-#endif
-
-#ifndef BTRFS_IOC_SUBVOL_SETFLAGS
-#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
-#endif
-
-#ifndef BTRFS_IOC_DEV_INFO
-#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
-                                 struct btrfs_ioctl_dev_info_args)
-#endif
-
-#ifndef BTRFS_IOC_FS_INFO
-#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
-                                 struct btrfs_ioctl_fs_info_args)
-#endif
-
-#ifndef BTRFS_IOC_DEVICES_READY
-#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \
-                                 struct btrfs_ioctl_vol_args)
-#endif
-
-#ifndef BTRFS_IOC_QUOTA_CTL
-#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \
-                               struct btrfs_ioctl_quota_ctl_args)
-#endif
-
-#ifndef BTRFS_IOC_QGROUP_LIMIT
-#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \
-                               struct btrfs_ioctl_qgroup_limit_args)
-#endif
-
-#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
-#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
-#endif
-
-#ifndef BTRFS_FIRST_FREE_OBJECTID
-#define BTRFS_FIRST_FREE_OBJECTID 256
-#endif
-
-#ifndef BTRFS_LAST_FREE_OBJECTID
-#define BTRFS_LAST_FREE_OBJECTID -256ULL
-#endif
-
-#ifndef BTRFS_ROOT_TREE_OBJECTID
-#define BTRFS_ROOT_TREE_OBJECTID 1
-#endif
-
-#ifndef BTRFS_QUOTA_TREE_OBJECTID
-#define BTRFS_QUOTA_TREE_OBJECTID 8ULL
-#endif
-
-#ifndef BTRFS_ROOT_ITEM_KEY
-#define BTRFS_ROOT_ITEM_KEY 132
-#endif
-
-#ifndef BTRFS_QGROUP_STATUS_KEY
-#define BTRFS_QGROUP_STATUS_KEY 240
-#endif
-
-#ifndef BTRFS_QGROUP_INFO_KEY
-#define BTRFS_QGROUP_INFO_KEY 242
-#endif
-
-#ifndef BTRFS_QGROUP_LIMIT_KEY
-#define BTRFS_QGROUP_LIMIT_KEY 244
-#endif
-
-#ifndef BTRFS_QGROUP_RELATION_KEY
-#define BTRFS_QGROUP_RELATION_KEY 246
-#endif
-
-#ifndef BTRFS_ROOT_BACKREF_KEY
-#define BTRFS_ROOT_BACKREF_KEY 144
-#endif
-
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-
-#ifndef CGROUP_SUPER_MAGIC
-#define CGROUP_SUPER_MAGIC 0x27e0eb
-#endif
-
-#ifndef CGROUP2_SUPER_MAGIC
-#define CGROUP2_SUPER_MAGIC 0x63677270
-#endif
-
-#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
-#endif
-
-#ifndef TMPFS_MAGIC
-#define TMPFS_MAGIC 0x01021994
-#endif
-
-#ifndef MQUEUE_MAGIC
-#define MQUEUE_MAGIC 0x19800202
-#endif
-
-#ifndef SECURITYFS_MAGIC
-#define SECURITYFS_MAGIC 0x73636673
-#endif
-
-#ifndef TRACEFS_MAGIC
-#define TRACEFS_MAGIC 0x74726163
-#endif
-
-#ifndef BPF_FS_MAGIC
-#define BPF_FS_MAGIC 0xcafe4a11
-#endif
-
-#ifndef OCFS2_SUPER_MAGIC
-#define OCFS2_SUPER_MAGIC 0x7461636f
-#endif
-
-#ifndef MS_MOVE
-#define MS_MOVE 8192
-#endif
-
-#ifndef MS_REC
-#define MS_REC 16384
-#endif
-
-#ifndef MS_PRIVATE
-#define MS_PRIVATE      (1<<18)
-#endif
-
-#ifndef MS_REC
-#define MS_REC          (1<<19)
-#endif
-
-#ifndef MS_SHARED
-#define MS_SHARED       (1<<20)
-#endif
-
-#ifndef MS_RELATIME
-#define MS_RELATIME     (1<<21)
-#endif
-
-#ifndef MS_KERNMOUNT
-#define MS_KERNMOUNT    (1<<22)
-#endif
-
-#ifndef MS_I_VERSION
-#define MS_I_VERSION    (1<<23)
-#endif
-
-#ifndef MS_STRICTATIME
-#define MS_STRICTATIME  (1<<24)
-#endif
-
-#ifndef MS_LAZYTIME
-#define MS_LAZYTIME     (1<<25)
-#endif
-
-#ifndef SCM_SECURITY
-#define SCM_SECURITY 0x03
-#endif
-
-#ifndef PR_SET_NO_NEW_PRIVS
-#define PR_SET_NO_NEW_PRIVS 38
-#endif
-
-#ifndef PR_SET_CHILD_SUBREAPER
-#define PR_SET_CHILD_SUBREAPER 36
-#endif
-
-#ifndef PR_SET_MM_ARG_START
-#define PR_SET_MM_ARG_START 8
-#endif
-
-#ifndef PR_SET_MM_ARG_END
-#define PR_SET_MM_ARG_END 9
-#endif
-
-#ifndef PR_SET_MM_ENV_START
-#define PR_SET_MM_ENV_START 10
-#endif
-
-#ifndef PR_SET_MM_ENV_END
-#define PR_SET_MM_ENV_END 11
-#endif
-
-#ifndef EFIVARFS_MAGIC
-#define EFIVARFS_MAGIC 0xde5e81e4
-#endif
-
-#ifndef SMACK_MAGIC
-#define SMACK_MAGIC 0x43415d53
-#endif
-
-#ifndef DM_DEFERRED_REMOVE
-#define DM_DEFERRED_REMOVE (1 << 17)
-#endif
-
-#ifndef MAX_HANDLE_SZ
-#define MAX_HANDLE_SZ 128
-#endif
-
-#if ! HAVE_SECURE_GETENV
-#  if HAVE___SECURE_GETENV
-#    define secure_getenv __secure_getenv
-#  else
-#    error "neither secure_getenv nor __secure_getenv are available"
-#  endif
-#endif
-
-#ifndef CIFS_MAGIC_NUMBER
-#  define CIFS_MAGIC_NUMBER 0xFF534D42
-#endif
-
-#ifndef TFD_TIMER_CANCEL_ON_SET
-#  define TFD_TIMER_CANCEL_ON_SET (1 << 1)
-#endif
-
-#ifndef SO_REUSEPORT
-#  define SO_REUSEPORT 15
-#endif
-
-#ifndef SO_PEERGROUPS
-#  define SO_PEERGROUPS 59
-#endif
-
-#ifndef EVIOCREVOKE
-#  define EVIOCREVOKE _IOW('E', 0x91, int)
-#endif
-
-#ifndef EVIOCSMASK
-
-struct input_mask {
-        uint32_t type;
-        uint32_t codes_size;
-        uint64_t codes_ptr;
-};
-
-#define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
-#endif
-
-#ifndef DRM_IOCTL_SET_MASTER
-#  define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
-#endif
-
-#ifndef DRM_IOCTL_DROP_MASTER
-#  define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
-#endif
-
-/* The precise definition of __O_TMPFILE is arch specific; use the
- * values defined by the kernel (note: some are hexa, some are octal,
- * duplicated as-is from the kernel definitions):
- * - alpha, parisc, sparc: each has a specific value;
- * - others: they use the "generic" value.
- */
-
-#ifndef __O_TMPFILE
-#if defined(__alpha__)
-#define __O_TMPFILE     0100000000
-#elif defined(__parisc__) || defined(__hppa__)
-#define __O_TMPFILE     0400000000
-#elif defined(__sparc__) || defined(__sparc64__)
-#define __O_TMPFILE     0x2000000
-#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
-
-#if !HAVE_LO_FLAGS_PARTSCAN
-#define LO_FLAGS_PARTSCAN 8
-#endif
-
-#ifndef LOOP_CTL_REMOVE
-#define LOOP_CTL_REMOVE 0x4C81
-#endif
-
-#ifndef LOOP_CTL_GET_FREE
-#define LOOP_CTL_GET_FREE 0x4C82
-#endif
-
-#if !HAVE_IFLA_INET6_ADDR_GEN_MODE
-#define IFLA_INET6_UNSPEC 0
-#define IFLA_INET6_FLAGS 1
-#define IFLA_INET6_CONF 2
-#define IFLA_INET6_STATS 3
-#define IFLA_INET6_MCAST 4
-#define IFLA_INET6_CACHEINFO 5
-#define IFLA_INET6_ICMP6STATS 6
-#define IFLA_INET6_TOKEN 7
-#define IFLA_INET6_ADDR_GEN_MODE 8
-#define __IFLA_INET6_MAX 9
-
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
-
-#define IN6_ADDR_GEN_MODE_EUI64 0
-#define IN6_ADDR_GEN_MODE_NONE 1
-#endif
-
-#if !HAVE_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
-#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2
-#endif
-
-#if !HAVE_IFLA_MACVLAN_FLAGS
-#define IFLA_MACVLAN_UNSPEC 0
-#define IFLA_MACVLAN_MODE 1
-#define IFLA_MACVLAN_FLAGS 2
-#define __IFLA_MACVLAN_MAX 3
-
-#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_IPVLAN_FLAGS
-#define IFLA_IPVLAN_UNSPEC 0
-#define IFLA_IPVLAN_MODE 1
-#define IFLA_IPVLAN_FLAGS 2
-#define __IFLA_IPVLAN_MAX 3
-
-#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
-
-#define IPVLAN_MODE_L2 0
-#define IPVLAN_MODE_L3 1
-#define IPVLAN_MODE_L3S 2
-#define IPVLAN_MAX 2
-#endif
-
-#if !HAVE_IPVLAN_F_PRIVATE
-#define IPVLAN_F_PRIVATE 0x01
-#define IPVLAN_F_VEPA    0x02
-#define __IPVLAN_F_PRIVATE_MAX 3
-
-#define HAVE_IPVLAN_F_PRIVATE_MAX (__HAVE_IPVLAN_F_PRIVATE_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_VTI_REMOTE
-#define IFLA_VTI_UNSPEC 0
-#define IFLA_VTI_LINK 1
-#define IFLA_VTI_IKEY 2
-#define IFLA_VTI_OKEY 3
-#define IFLA_VTI_LOCAL 4
-#define IFLA_VTI_REMOTE 5
-#define __IFLA_VTI_MAX 6
-
-#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_PHYS_PORT_ID
-#define IFLA_EXT_MASK 29
-#undef IFLA_PROMISCUITY
-#define IFLA_PROMISCUITY 30
-#define IFLA_NUM_TX_QUEUES 31
-#define IFLA_NUM_RX_QUEUES 32
-#define IFLA_CARRIER 33
-#define IFLA_PHYS_PORT_ID 34
-#define __IFLA_MAX 35
-
-#define IFLA_MAX (__IFLA_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_BOND_AD_ACTOR_SYSTEM
-#define IFLA_BOND_UNSPEC 0
-#define IFLA_BOND_MODE 1
-#define IFLA_BOND_ACTIVE_SLAVE 2
-#define IFLA_BOND_MIIMON 3
-#define IFLA_BOND_UPDELAY 4
-#define IFLA_BOND_DOWNDELAY 5
-#define IFLA_BOND_USE_CARRIER 6
-#define IFLA_BOND_ARP_INTERVAL 7
-#define IFLA_BOND_ARP_IP_TARGET 8
-#define IFLA_BOND_ARP_VALIDATE 9
-#define IFLA_BOND_ARP_ALL_TARGETS 10
-#define IFLA_BOND_PRIMARY 11
-#define IFLA_BOND_PRIMARY_RESELECT 12
-#define IFLA_BOND_FAIL_OVER_MAC 13
-#define IFLA_BOND_XMIT_HASH_POLICY 14
-#define IFLA_BOND_RESEND_IGMP 15
-#define IFLA_BOND_NUM_PEER_NOTIF 16
-#define IFLA_BOND_ALL_SLAVES_ACTIVE 17
-#define IFLA_BOND_MIN_LINKS 18
-#define IFLA_BOND_LP_INTERVAL 19
-#define IFLA_BOND_PACKETS_PER_SLAVE 20
-#define IFLA_BOND_AD_LACP_RATE 21
-#define IFLA_BOND_AD_SELECT 22
-#define IFLA_BOND_AD_INFO 23
-#define IFLA_BOND_AD_ACTOR_SYS_PRIO 24
-#define IFLA_BOND_AD_USER_PORT_KEY 25
-#define IFLA_BOND_AD_ACTOR_SYSTEM 26
-#define __IFLA_BOND_MAX 27
-
-#define IFLA_BOND_MAX   (__IFLA_BOND_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_VLAN_PROTOCOL
-#define IFLA_VLAN_UNSPEC 0
-#define IFLA_VLAN_ID 1
-#define IFLA_VLAN_FLAGS 2
-#define IFLA_VLAN_EGRESS_QOS 3
-#define IFLA_VLAN_INGRESS_QOS 4
-#define IFLA_VLAN_PROTOCOL 5
-#define __IFLA_VLAN_MAX 6
-
-#define IFLA_VLAN_MAX   (__IFLA_VLAN_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_VXLAN_GPE
-#define IFLA_VXLAN_UNSPEC 0
-#define IFLA_VXLAN_ID 1
-#define IFLA_VXLAN_GROUP 2
-#define IFLA_VXLAN_LINK 3
-#define IFLA_VXLAN_LOCAL 4
-#define IFLA_VXLAN_TTL 5
-#define IFLA_VXLAN_TOS 6
-#define IFLA_VXLAN_LEARNING 7
-#define IFLA_VXLAN_AGEING 8
-#define IFLA_VXLAN_LIMIT 9
-#define IFLA_VXLAN_PORT_RANGE 10
-#define IFLA_VXLAN_PROXY 11
-#define IFLA_VXLAN_RSC 12
-#define IFLA_VXLAN_L2MISS 13
-#define IFLA_VXLAN_L3MISS 14
-#define IFLA_VXLAN_PORT 15
-#define IFLA_VXLAN_GROUP6 16
-#define IFLA_VXLAN_LOCAL6 17
-#define IFLA_VXLAN_UDP_CSUM 18
-#define IFLA_VXLAN_UDP_ZERO_CSUM6_TX 19
-#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX 20
-#define IFLA_VXLAN_REMCSUM_TX 21
-#define IFLA_VXLAN_REMCSUM_RX 22
-#define IFLA_VXLAN_GBP 23
-#define IFLA_VXLAN_REMCSUM_NOPARTIAL 24
-#define IFLA_VXLAN_COLLECT_METADATA 25
-#define IFLA_VXLAN_LABEL 26
-#define IFLA_VXLAN_GPE 27
-
-#define __IFLA_VXLAN_MAX 28
-
-#define IFLA_VXLAN_MAX  (__IFLA_VXLAN_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_GENEVE_LABEL
-#define IFLA_GENEVE_UNSPEC 0
-#define IFLA_GENEVE_ID 1
-#define IFLA_GENEVE_REMOTE 2
-#define IFLA_GENEVE_TTL 3
-#define IFLA_GENEVE_TOS 4
-#define IFLA_GENEVE_PORT 5
-#define IFLA_GENEVE_COLLECT_METADATA 6
-#define IFLA_GENEVE_REMOTE6 7
-#define IFLA_GENEVE_UDP_CSUM 8
-#define IFLA_GENEVE_UDP_ZERO_CSUM6_TX 9
-#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
-#define IFLA_GENEVE_LABEL 11
-
-#define __IFLA_GENEVE_MAX 12
-
-#define IFLA_GENEVE_MAX  (__IFLA_GENEVE_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_IPTUN_ENCAP_DPORT
-#define IFLA_IPTUN_UNSPEC 0
-#define IFLA_IPTUN_LINK 1
-#define IFLA_IPTUN_LOCAL 2
-#define IFLA_IPTUN_REMOTE 3
-#define IFLA_IPTUN_TTL 4
-#define IFLA_IPTUN_TOS 5
-#define IFLA_IPTUN_ENCAP_LIMIT 6
-#define IFLA_IPTUN_FLOWINFO 7
-#define IFLA_IPTUN_FLAGS 8
-#define IFLA_IPTUN_PROTO 9
-#define IFLA_IPTUN_PMTUDISC 10
-#define IFLA_IPTUN_6RD_PREFIX 11
-#define IFLA_IPTUN_6RD_RELAY_PREFIX 12
-#define IFLA_IPTUN_6RD_PREFIXLEN 13
-#define IFLA_IPTUN_6RD_RELAY_PREFIXLEN 14
-#define IFLA_IPTUN_ENCAP_TYPE 15
-#define IFLA_IPTUN_ENCAP_FLAGS 16
-#define IFLA_IPTUN_ENCAP_SPORT 17
-#define IFLA_IPTUN_ENCAP_DPORT 18
-
-#define __IFLA_IPTUN_MAX 19
-
-#define IFLA_IPTUN_MAX  (__IFLA_IPTUN_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_GRE_ERSPAN_HWID
-#define IFLA_GRE_UNSPEC 0
-#define IFLA_GRE_LINK 1
-#define IFLA_GRE_IFLAGS 2
-#define IFLA_GRE_OFLAGS 3
-#define IFLA_GRE_IKEY 4
-#define IFLA_GRE_OKEY 5
-#define IFLA_GRE_LOCAL 6
-#define IFLA_GRE_REMOTE 7
-#define IFLA_GRE_TTL 8
-#define IFLA_GRE_TOS 9
-#define IFLA_GRE_PMTUDISC 10
-#define IFLA_GRE_ENCAP_LIMIT 11
-#define IFLA_GRE_FLOWINFO 12
-#define IFLA_GRE_FLAGS 13
-#define IFLA_GRE_ENCAP_TYPE 14
-#define IFLA_GRE_ENCAP_FLAGS 15
-#define IFLA_GRE_ENCAP_SPORT 16
-#define IFLA_GRE_ENCAP_DPORT 17
-#define IFLA_GRE_COLLECT_METADATA 18
-#define IFLA_GRE_IGNORE_DF 19
-#define IFLA_GRE_FWMARK 20
-#define IFLA_GRE_ERSPAN_INDEX 21
-#define IFLA_GRE_ERSPAN_VER 22
-#define IFLA_GRE_ERSPAN_DIR 23
-#define IFLA_GRE_ERSPAN_HWID 24
-#define __IFLA_GRE_MAX 25
-
-#define IFLA_GRE_MAX  (__IFLA_GRE_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_BRIDGE_VLAN_INFO
-#define IFLA_BRIDGE_FLAGS 0
-#define IFLA_BRIDGE_MODE 1
-#define IFLA_BRIDGE_VLAN_INFO 2
-#define __IFLA_BRIDGE_MAX 3
-
-#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
-#endif
-
-#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
-#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
-#endif
-
-#ifndef BRIDGE_VLAN_INFO_RANGE_END
-#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
-#endif
-
-#if !HAVE_IFLA_BR_VLAN_DEFAULT_PVID
-#define IFLA_BR_UNSPEC 0
-#define IFLA_BR_FORWARD_DELAY 1
-#define IFLA_BR_HELLO_TIME 2
-#define IFLA_BR_MAX_AGE 3
-#define IFLA_BR_AGEING_TIME 4
-#define IFLA_BR_STP_STATE 5
-#define IFLA_BR_PRIORITY 6
-#define IFLA_BR_VLAN_FILTERING 7
-#define IFLA_BR_VLAN_PROTOCOL 8
-#define IFLA_BR_GROUP_FWD_MASK 9
-#define IFLA_BR_ROOT_ID 10
-#define IFLA_BR_BRIDGE_ID 11
-#define IFLA_BR_ROOT_PORT 12
-#define IFLA_BR_ROOT_PATH_COST 13
-#define IFLA_BR_TOPOLOGY_CHANGE 14
-#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED 15
-#define IFLA_BR_HELLO_TIMER 16
-#define IFLA_BR_TCN_TIMER 17
-#define IFLA_BR_TOPOLOGY_CHANGE_TIMER 18
-#define IFLA_BR_GC_TIMER 19
-#define IFLA_BR_GROUP_ADDR 20
-#define IFLA_BR_FDB_FLUSH 21
-#define IFLA_BR_MCAST_ROUTER 22
-#define IFLA_BR_MCAST_SNOOPING 23
-#define IFLA_BR_MCAST_QUERY_USE_IFADDR 24
-#define IFLA_BR_MCAST_QUERIER 25
-#define IFLA_BR_MCAST_HASH_ELASTICITY 26
-#define IFLA_BR_MCAST_HASH_MAX 27
-#define IFLA_BR_MCAST_LAST_MEMBER_CNT 28
-#define IFLA_BR_MCAST_STARTUP_QUERY_CNT 29
-#define IFLA_BR_MCAST_LAST_MEMBER_INTVL 30
-#define IFLA_BR_MCAST_MEMBERSHIP_INTVL 31
-#define IFLA_BR_MCAST_QUERIER_INTVL 32
-#define IFLA_BR_MCAST_QUERY_INTVL 33
-#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34
-#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL 35
-#define IFLA_BR_NF_CALL_IPTABLES 36
-#define IFLA_BR_NF_CALL_IP6TABLES 37
-#define IFLA_BR_NF_CALL_ARPTABLES 38
-#define IFLA_BR_VLAN_DEFAULT_PVID 39
-#define __IFLA_BR_MAX 40
-
-#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_BRPORT_LEARNING_SYNC
-#define IFLA_BRPORT_UNSPEC 0
-#define IFLA_BRPORT_STATE 1
-#define IFLA_BRPORT_PRIORITY 2
-#define IFLA_BRPORT_COST 3
-#define IFLA_BRPORT_MODE 4
-#define IFLA_BRPORT_GUARD 5
-#define IFLA_BRPORT_PROTECT 6
-#define IFLA_BRPORT_FAST_LEAVE 7
-#define IFLA_BRPORT_LEARNING 8
-#define IFLA_BRPORT_UNICAST_FLOOD 9
-#define IFLA_BRPORT_LEARNING_SYNC 11
-#define __IFLA_BRPORT_MAX 12
-
-#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
-#endif
-
-#if !HAVE_FRA_DPORT_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_PROTOCOL 21
-#define FRA_IP_PROTO 22
-#define FRA_SPORT_RANGE 23
-#define FRA_DPORT_RANGE 24
-#define __FRA_MAX 25
-
-#define FRA_MAX (__FRA_MAX - 1)
-#endif
-
-#if !HAVE_IFLA_BRPORT_PROXYARP
-#define IFLA_BRPORT_PROXYARP 10
-#endif
-
-#if !HAVE_IFLA_VRF_TABLE
-#define IFLA_VRF_TABLE 1
-#endif
-
-#if !HAVE_VXCAN_INFO_PEER
-#define VXCAN_INFO_PEER 1
-#endif
-
-#if !HAVE_NDA_IFINDEX
-#define NDA_UNSPEC 0
-#define NDA_DST 1
-#define NDA_LLADDR 2
-#define NDA_CACHEINFO 3
-#define NDA_PROBES 4
-#define NDA_VLAN 5
-#define NDA_PORT 6
-#define NDA_VNI 7
-#define NDA_IFINDEX 8
-#define __NDA_MAX 9
-
-#define NDA_MAX (__NDA_MAX - 1)
-#endif
-
-#ifndef RTA_PREF
-#define RTA_PREF 20
-#endif
-
-#ifndef RTAX_QUICKACK
-#define RTAX_QUICKACK 15
-#endif
-
-#ifndef RTA_EXPIRES
-#define RTA_EXPIRES 23
-#endif
-
-#ifndef IPV6_UNICAST_IF
-#define IPV6_UNICAST_IF 76
-#endif
-
-#ifndef IPV6_MIN_MTU
-#define IPV6_MIN_MTU 1280
-#endif
-
-#ifndef IPV4_MIN_MTU
-#define IPV4_MIN_MTU 68
-#endif
-
-#ifndef IFF_MULTI_QUEUE
-#define IFF_MULTI_QUEUE 0x100
-#endif
-
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP 0x10000
-#endif
-
-#ifndef IFF_DORMANT
-#define IFF_DORMANT 0x20000
-#endif
-
-#ifndef BOND_XMIT_POLICY_ENCAP23
-#define BOND_XMIT_POLICY_ENCAP23 3
-#endif
-
-#ifndef BOND_XMIT_POLICY_ENCAP34
-#define BOND_XMIT_POLICY_ENCAP34 4
-#endif
-
-#ifndef NET_ADDR_RANDOM
-#  define NET_ADDR_RANDOM 1
-#endif
-
-#ifndef NET_NAME_UNKNOWN
-#  define NET_NAME_UNKNOWN 0
-#endif
-
-#ifndef NET_NAME_ENUM
-#  define NET_NAME_ENUM 1
-#endif
-
-#ifndef NET_NAME_PREDICTABLE
-#  define NET_NAME_PREDICTABLE 2
-#endif
-
-#ifndef NET_NAME_USER
-#  define NET_NAME_USER 3
-#endif
-
-#ifndef NET_NAME_RENAMED
-#  define NET_NAME_RENAMED 4
-#endif
-
-#ifndef BPF_XOR
-#  define BPF_XOR 0xa0
-#endif
-
-/* Note that LOOPBACK_IFINDEX is currently not exported by the
- * kernel/glibc, but hardcoded internally by the kernel.  However, as
- * it is exported to userspace indirectly via rtnetlink and the
- * ioctls, and made use of widely we define it here too, in a way that
- * is compatible with the kernel's internal definition. */
-#ifndef LOOPBACK_IFINDEX
-#define LOOPBACK_IFINDEX 1
-#endif
-
-#if !HAVE_IFA_FLAGS
-#define IFA_FLAGS 8
-#endif
-
-#ifndef IFA_F_MANAGETEMPADDR
-#define IFA_F_MANAGETEMPADDR 0x100
-#endif
-
-#ifndef IFA_F_NOPREFIXROUTE
-#define IFA_F_NOPREFIXROUTE 0x200
-#endif
-
-#ifndef MAX_AUDIT_MESSAGE_LENGTH
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
-#endif
-
-#ifndef AUDIT_NLGRP_MAX
-#define AUDIT_NLGRP_READLOG 1
-#endif
-
-#ifndef CAP_MAC_OVERRIDE
-#define CAP_MAC_OVERRIDE 32
-#endif
-
-#ifndef CAP_MAC_ADMIN
-#define CAP_MAC_ADMIN 33
-#endif
-
-#ifndef CAP_SYSLOG
-#define CAP_SYSLOG 34
-#endif
-
-#ifndef CAP_WAKE_ALARM
-#define CAP_WAKE_ALARM 35
-#endif
-
-#ifndef CAP_BLOCK_SUSPEND
-#define CAP_BLOCK_SUSPEND 36
-#endif
-
-#ifndef CAP_AUDIT_READ
-#define CAP_AUDIT_READ 37
-#endif
-
-#ifndef RENAME_NOREPLACE
-#define RENAME_NOREPLACE (1 << 0)
-#endif
-
-#ifndef KCMP_FILE
-#define KCMP_FILE 0
-#endif
-
-#ifndef INPUT_PROP_POINTING_STICK
-#define INPUT_PROP_POINTING_STICK 0x05
-#endif
-
-#ifndef INPUT_PROP_ACCELEROMETER
-#define INPUT_PROP_ACCELEROMETER  0x06
-#endif
-
-#ifndef BTN_DPAD_UP
-#define BTN_DPAD_UP 0x220
-#define BTN_DPAD_RIGHT 0x223
-#endif
-
-#ifndef KEY_ALS_TOGGLE
-#define KEY_ALS_TOGGLE 0x230
-#endif
-
-typedef int32_t key_serial_t;
-
-#ifndef KEYCTL_JOIN_SESSION_KEYRING
-#define KEYCTL_JOIN_SESSION_KEYRING 1
-#endif
-
-#ifndef KEYCTL_CHOWN
-#define KEYCTL_CHOWN 4
-#endif
-
-#ifndef KEYCTL_SETPERM
-#define KEYCTL_SETPERM 5
-#endif
-
-#ifndef KEYCTL_DESCRIBE
-#define KEYCTL_DESCRIBE 6
-#endif
-
-#ifndef KEYCTL_LINK
-#define KEYCTL_LINK 8
-#endif
-
-#ifndef KEYCTL_READ
-#define KEYCTL_READ 11
-#endif
-
-#ifndef KEYCTL_SET_TIMEOUT
-#define KEYCTL_SET_TIMEOUT 15
-#endif
-
-#ifndef KEY_POS_VIEW
-#define KEY_POS_VIEW    0x01000000
-#define KEY_POS_READ    0x02000000
-#define KEY_POS_WRITE   0x04000000
-#define KEY_POS_SEARCH  0x08000000
-#define KEY_POS_LINK    0x10000000
-#define KEY_POS_SETATTR 0x20000000
-
-#define KEY_USR_VIEW    0x00010000
-#define KEY_USR_READ    0x00020000
-#define KEY_USR_WRITE   0x00040000
-#define KEY_USR_SEARCH  0x00080000
-#define KEY_USR_LINK    0x00100000
-#define KEY_USR_SETATTR 0x00200000
-
-#define KEY_GRP_VIEW    0x00000100
-#define KEY_GRP_READ    0x00000200
-#define KEY_GRP_WRITE   0x00000400
-#define KEY_GRP_SEARCH  0x00000800
-#define KEY_GRP_LINK    0x00001000
-#define KEY_GRP_SETATTR 0x00002000
-
-#define KEY_OTH_VIEW    0x00000001
-#define KEY_OTH_READ    0x00000002
-#define KEY_OTH_WRITE   0x00000004
-#define KEY_OTH_SEARCH  0x00000008
-#define KEY_OTH_LINK    0x00000010
-#define KEY_OTH_SETATTR 0x00000020
-#endif
-
-#ifndef KEY_SPEC_USER_KEYRING
-#define KEY_SPEC_USER_KEYRING -4
-#endif
-
-#ifndef KEY_SPEC_SESSION_KEYRING
-#define KEY_SPEC_SESSION_KEYRING -3
-#endif
-
-#ifndef PR_CAP_AMBIENT
-#define PR_CAP_AMBIENT 47
-#endif
-
-#ifndef PR_CAP_AMBIENT_IS_SET
-#define PR_CAP_AMBIENT_IS_SET 1
-#endif
-
-#ifndef PR_CAP_AMBIENT_RAISE
-#define PR_CAP_AMBIENT_RAISE 2
-#endif
-
-#ifndef PR_CAP_AMBIENT_CLEAR_ALL
-#define PR_CAP_AMBIENT_CLEAR_ALL 4
-#endif
-
-/* The following two defines are actually available in the kernel headers for longer, but we define them here anyway,
- * since that makes it easier to use them in conjunction with the glibc net/if.h header which conflicts with
- * linux/if.h. */
-#ifndef IF_OPER_UNKNOWN
-#define IF_OPER_UNKNOWN 0
-#endif
-
-#ifndef IF_OPER_UP
-#define IF_OPER_UP 6
-
-#if ! HAVE_CHAR32_T
-#define char32_t uint32_t
-#endif
-
-#if ! HAVE_CHAR16_T
-#define char16_t uint16_t
-#endif
-
-#ifndef ETHERTYPE_LLDP
-#define ETHERTYPE_LLDP 0x88cc
-#endif
-
-#ifndef IFA_F_MCAUTOJOIN
-#define IFA_F_MCAUTOJOIN 0x400
-#endif
-
-#if ! HAVE_STRUCT_FIB_RULE_UID_RANGE
-
-struct fib_rule_uid_range {
-        __u32 start;
-        __u32 end;
-};
-
-#endif
-
-#if ! HAVE_STRUCT_FIB_RULE_PORT_RANGE
-
-struct fib_rule_port_range {
-        __u16 start;
-        __u16 end;
-};
-
-#endif
-
-#endif
-
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-
-#ifndef AF_VSOCK
-#define AF_VSOCK 40
-#endif
-
-#ifndef EXT4_IOC_RESIZE_FS
-#  define EXT4_IOC_RESIZE_FS              _IOW('f', 16, __u64)
-#endif
-
-#ifndef NSFS_MAGIC
-#define NSFS_MAGIC 0x6e736673
-#endif
-
-#ifndef NS_GET_NSTYPE
-#define NS_GET_NSTYPE _IO(0xb7, 0x3)
-#endif
-
-#ifndef FALLOC_FL_KEEP_SIZE
-#define FALLOC_FL_KEEP_SIZE 0x01
-#endif
-
-#ifndef FALLOC_FL_PUNCH_HOLE
-#define FALLOC_FL_PUNCH_HOLE 0x02
-#endif
-
-#ifndef PF_KTHREAD
-#define PF_KTHREAD 0x00200000
-#endif
-
-#if ! HAVE_STRUCT_STATX
-struct statx_timestamp {
-        int64_t tv_sec;
-        uint32_t tv_nsec;
-        uint32_t __reserved;
-};
-struct statx {
-        uint32_t stx_mask;
-        uint32_t stx_blksize;
-        uint64_t stx_attributes;
-        uint32_t stx_nlink;
-        uint32_t stx_uid;
-        uint32_t stx_gid;
-        uint16_t stx_mode;
-        uint16_t __spare0[1];
-        uint64_t stx_ino;
-        uint64_t stx_size;
-        uint64_t stx_blocks;
-        uint64_t stx_attributes_mask;
-        struct statx_timestamp stx_atime;
-        struct statx_timestamp stx_btime;
-        struct statx_timestamp stx_ctime;
-        struct statx_timestamp stx_mtime;
-        uint32_t stx_rdev_major;
-        uint32_t stx_rdev_minor;
-        uint32_t stx_dev_major;
-        uint32_t stx_dev_minor;
-        uint64_t __spare2[14];
-};
-#endif
-
-#ifndef STATX_BTIME
-#define STATX_BTIME 0x00000800U
-#endif
-
-#ifndef AT_STATX_DONT_SYNC
-#define AT_STATX_DONT_SYNC 0x4000
-#endif
-
-/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of the same
- * name, which we need in userspace at various places but is not defined in userspace currently, neither under this
- * name nor any other. */
-#ifndef TASK_COMM_LEN
-#define TASK_COMM_LEN 16
-#endif
-
-#ifndef FOU_GENL_NAME
-#define FOU_GENL_NAME           "fou"
-#endif
-
-#ifndef FOU_GENL_VERSION
-#define FOU_GENL_VERSION        0x1
-#endif
-
-#if !HAVE_LINUX_FOU_H
-#define FOU_ATTR_UNSPEC            0
-#define FOU_ATTR_PORT              1
-#define FOU_ATTR_AF                2
-#define FOU_ATTR_IPPROTO           3
-#define FOU_ATTR_TYPE              4
-#endif
-#if !HAVE_FOU_ATTR_REMCSUM_NOPARTIAL
-#define FOU_ATTR_REMCSUM_NOPARTIAL 5
-#undef  FOU_ATTR_MAX
-#endif
-#ifndef FOU_ATTR_MAX
-#define FOU_ATTR_MAX               5
-#endif
-
-#if !HAVE_LINUX_FOU_H
-#define FOU_CMD_UNSPEC             0
-#define FOU_CMD_ADD                1
-#define FOU_CMD_DEL                2
-#endif
-#if !HAVE_FOU_CMD_GET
-#define FOU_CMD_GET                3
-#undef  FOU_CMD_MAX
-#endif
-#ifndef FOU_CMD_MAX
-#define FOU_CMD_MAX                3
-#endif
-
-#if !HAVE_LINUX_FOU_H
-#define FOU_ENCAP_UNSPEC           0
-#define FOU_ENCAP_DIRECT           1
-#define FOU_ENCAP_GUE              2
-#define __FOU_ENCAP_MAX            3
-
-#define FOU_ENCAP_MAX (__FOU_ENCAP_MAX - 1)
-#endif
-
-#if !HAVE_ETHTOOL_LINK_MODE_10baseT_Half_BIT /* linux@3f1ac7a700d039c61d8d8b99f28d605d489a60cf (4.6) */
-
-#define ETHTOOL_GLINKSETTINGS   0x0000004c /* Get ethtool_link_settings */
-#define ETHTOOL_SLINKSETTINGS   0x0000004d /* Set ethtool_link_settings */
-
-struct ethtool_link_settings {
-        __u32 cmd;
-        __u32 speed;
-        __u8  duplex;
-        __u8  port;
-        __u8  phy_address;
-        __u8  autoneg;
-        __u8  mdio_support;
-        __u8  eth_tp_mdix;
-        __u8  eth_tp_mdix_ctrl;
-        __s8  link_mode_masks_nwords;
-        __u8  transceiver;
-        __u8  reserved1[3];
-        __u32 reserved[7];
-        __u32 link_mode_masks[0];
-        /* layout of link_mode_masks fields:
-         * __u32 map_supported[link_mode_masks_nwords];
-         * __u32 map_advertising[link_mode_masks_nwords];
-         * __u32 map_lp_advertising[link_mode_masks_nwords];
-         */
-};
-
-enum ethtool_link_mode_bit_indices {
-        ETHTOOL_LINK_MODE_10baseT_Half_BIT           = 0,
-        ETHTOOL_LINK_MODE_10baseT_Full_BIT           = 1,
-        ETHTOOL_LINK_MODE_100baseT_Half_BIT          = 2,
-        ETHTOOL_LINK_MODE_100baseT_Full_BIT          = 3,
-        ETHTOOL_LINK_MODE_1000baseT_Half_BIT         = 4,
-        ETHTOOL_LINK_MODE_1000baseT_Full_BIT         = 5,
-        ETHTOOL_LINK_MODE_Autoneg_BIT                = 6,
-        ETHTOOL_LINK_MODE_TP_BIT                     = 7,
-        ETHTOOL_LINK_MODE_AUI_BIT                    = 8,
-        ETHTOOL_LINK_MODE_MII_BIT                    = 9,
-        ETHTOOL_LINK_MODE_FIBRE_BIT                  = 10,
-        ETHTOOL_LINK_MODE_BNC_BIT                    = 11,
-        ETHTOOL_LINK_MODE_10000baseT_Full_BIT        = 12,
-        ETHTOOL_LINK_MODE_Pause_BIT                  = 13,
-        ETHTOOL_LINK_MODE_Asym_Pause_BIT             = 14,
-        ETHTOOL_LINK_MODE_2500baseX_Full_BIT         = 15,
-        ETHTOOL_LINK_MODE_Backplane_BIT              = 16,
-        ETHTOOL_LINK_MODE_1000baseKX_Full_BIT        = 17,
-        ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT      = 18,
-        ETHTOOL_LINK_MODE_10000baseKR_Full_BIT       = 19,
-        ETHTOOL_LINK_MODE_10000baseR_FEC_BIT         = 20,
-        ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT     = 21,
-        ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT      = 22,
-        ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT      = 23,
-        ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT      = 24,
-        ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT      = 25,
-        ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT      = 26,
-        ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT      = 27,
-        ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT      = 28,
-        ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT      = 29,
-        ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT      = 30,
-        ETHTOOL_LINK_MODE_25000baseCR_Full_BIT       = 31,
-        ETHTOOL_LINK_MODE_25000baseKR_Full_BIT       = 32,
-        ETHTOOL_LINK_MODE_25000baseSR_Full_BIT       = 33,
-        ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT      = 34,
-        ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT      = 35,
-        ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT     = 36,
-        ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT     = 37,
-        ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT     = 38,
-        ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39,
-        ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT      = 40,
-        ETHTOOL_LINK_MODE_1000baseX_Full_BIT         = 41,
-        ETHTOOL_LINK_MODE_10000baseCR_Full_BIT       = 42,
-        ETHTOOL_LINK_MODE_10000baseSR_Full_BIT       = 43,
-        ETHTOOL_LINK_MODE_10000baseLR_Full_BIT       = 44,
-        ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT      = 45,
-        ETHTOOL_LINK_MODE_10000baseER_Full_BIT       = 46,
-        ETHTOOL_LINK_MODE_2500baseT_Full_BIT         = 47,
-        ETHTOOL_LINK_MODE_5000baseT_Full_BIT         = 48,
-
-        ETHTOOL_LINK_MODE_FEC_NONE_BIT               = 49,
-        ETHTOOL_LINK_MODE_FEC_RS_BIT                 = 50,
-        ETHTOOL_LINK_MODE_FEC_BASER_BIT              = 51,
-
-        /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
-         * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
-         * macro for bits > 31. The only way to use indices > 31 is to
-         * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
-         */
-
-        __ETHTOOL_LINK_MODE_LAST
-          = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
-};
-#else
-#if !HAVE_ETHTOOL_LINK_MODE_25000baseCR_Full_BIT /* linux@3851112e4737cd52aaeda0ce8d084be9ee128106 (4.7) */
-#define ETHTOOL_LINK_MODE_25000baseCR_Full_BIT       31
-#define ETHTOOL_LINK_MODE_25000baseKR_Full_BIT       32
-#define ETHTOOL_LINK_MODE_25000baseSR_Full_BIT       33
-#define ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT      34
-#define ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT      35
-#define ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT     36
-#define ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT     37
-#define ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT     38
-#define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
-#endif
-#if !HAVE_ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT /* linux@89da45b8b5b2187734a11038b8593714f964ffd1 (4.8) */
-#define ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT      40
-#endif
-#if !HAVE_ETHTOOL_LINK_MODE_1000baseX_Full_BIT /* linux@5711a98221443aec54c4c81ee98c6ae46acccb65 (4.9) */
-#define ETHTOOL_LINK_MODE_1000baseX_Full_BIT         41
-#define ETHTOOL_LINK_MODE_10000baseCR_Full_BIT       42
-#define ETHTOOL_LINK_MODE_10000baseSR_Full_BIT       43
-#define ETHTOOL_LINK_MODE_10000baseLR_Full_BIT       44
-#define ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT      45
-#define ETHTOOL_LINK_MODE_10000baseER_Full_BIT       46
-#endif
-#if !HAVE_ETHTOOL_LINK_MODE_2500baseT_Full_BIT /* linux@94842b4fc4d6b1691cfc86c6f5251f299d27f4ba (4.10) */
-#define ETHTOOL_LINK_MODE_2500baseT_Full_BIT         47
-#define ETHTOOL_LINK_MODE_5000baseT_Full_BIT         48
-#endif
-#if !HAVE_ETHTOOL_LINK_MODE_FEC_NONE_BIT /* linux@1a5f3da20bd966220931239fbd31e6ac6ff42251 (4.14) */
-#define ETHTOOL_LINK_MODE_FEC_NONE_BIT               49
-#define ETHTOOL_LINK_MODE_FEC_RS_BIT                 50
-#define ETHTOOL_LINK_MODE_FEC_BASER_BIT              51
-#endif
-#endif
+#include "missing_audit.h"
+#include "missing_btrfs_tree.h"
+#include "missing_capability.h"
+#include "missing_drm.h"
+#include "missing_fcntl.h"
+#include "missing_fs.h"
+#include "missing_input.h"
+#include "missing_magic.h"
+#include "missing_mman.h"
+#include "missing_network.h"
+#include "missing_prctl.h"
+#include "missing_random.h"
+#include "missing_resource.h"
+#include "missing_sched.h"
+#include "missing_socket.h"
+#include "missing_stdlib.h"
+#include "missing_timerfd.h"
+#include "missing_type.h"
 
 #include "missing_syscall.h"
diff --git a/src/basic/missing_audit.h b/src/basic/missing_audit.h
new file mode 100644 (file)
index 0000000..b00d537
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/audit.h>
+
+#if HAVE_AUDIT
+#include <libaudit.h>
+#endif
+
+#ifndef AUDIT_SERVICE_START
+#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+#endif
+
+#ifndef AUDIT_SERVICE_STOP
+#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+#endif
+
+#ifndef MAX_AUDIT_MESSAGE_LENGTH
+#define MAX_AUDIT_MESSAGE_LENGTH 8970
+#endif
+
+#ifndef AUDIT_NLGRP_MAX
+#define AUDIT_NLGRP_READLOG 1
+#endif
diff --git a/src/basic/missing_btrfs.h b/src/basic/missing_btrfs.h
new file mode 100644 (file)
index 0000000..34c382f
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+/* Old btrfs.h requires stddef.h to be included before btrfs.h */
+#include <stddef.h>
+
+#include <linux/btrfs.h>
+
+/* linux@57254b6ebce4ceca02d9c8b615f6059c56c19238 (3.11) */
+#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
+#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
+#endif
+
+/* linux@83288b60bf6668933689078973136e0c9d387b38 (4.7) */
+#ifndef BTRFS_QGROUP_LIMIT_MAX_RFER
+#define BTRFS_QGROUP_LIMIT_MAX_RFER    (1ULL << 0)
+#define BTRFS_QGROUP_LIMIT_MAX_EXCL    (1ULL << 1)
+#define BTRFS_QGROUP_LIMIT_RSV_RFER    (1ULL << 2)
+#define BTRFS_QGROUP_LIMIT_RSV_EXCL    (1ULL << 3)
+#define BTRFS_QGROUP_LIMIT_RFER_CMPR   (1ULL << 4)
+#define BTRFS_QGROUP_LIMIT_EXCL_CMPR   (1ULL << 5)
+#endif
diff --git a/src/basic/missing_btrfs_tree.h b/src/basic/missing_btrfs_tree.h
new file mode 100644 (file)
index 0000000..555f90f
--- /dev/null
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/types.h>
+
+#include "missing_btrfs.h"
+
+/* linux@db6711600e27c885aed89751f04e727f3af26715 (4.7) */
+#if HAVE_LINUX_BTRFS_TREE_H
+#include <linux/btrfs_tree.h>
+#else
+#define BTRFS_ROOT_TREE_OBJECTID  1
+#define BTRFS_QUOTA_TREE_OBJECTID 8
+#define BTRFS_FIRST_FREE_OBJECTID 256
+#define BTRFS_LAST_FREE_OBJECTID -256ULL
+
+#define BTRFS_ROOT_ITEM_KEY       132
+#define BTRFS_ROOT_BACKREF_KEY    144
+#define BTRFS_QGROUP_STATUS_KEY   240
+#define BTRFS_QGROUP_INFO_KEY     242
+#define BTRFS_QGROUP_LIMIT_KEY    244
+#define BTRFS_QGROUP_RELATION_KEY 246
+
+struct btrfs_disk_key {
+        __le64 objectid;
+        __u8 type;
+        __le64 offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_timespec {
+        __le64 sec;
+        __le32 nsec;
+} __attribute__ ((__packed__));
+
+struct btrfs_inode_item {
+        __le64 generation;
+        __le64 transid;
+        __le64 size;
+        __le64 nbytes;
+        __le64 block_group;
+        __le32 nlink;
+        __le32 uid;
+        __le32 gid;
+        __le32 mode;
+        __le64 rdev;
+        __le64 flags;
+        __le64 sequence;
+        __le64 reserved[4];
+        struct btrfs_timespec atime;
+        struct btrfs_timespec ctime;
+        struct btrfs_timespec mtime;
+        struct btrfs_timespec otime;
+} __attribute__ ((__packed__));
+
+#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0)
+
+struct btrfs_root_item {
+        struct btrfs_inode_item inode;
+        __le64 generation;
+        __le64 root_dirid;
+        __le64 bytenr;
+        __le64 byte_limit;
+        __le64 bytes_used;
+        __le64 last_snapshot;
+        __le64 flags;
+        __le32 refs;
+        struct btrfs_disk_key drop_progress;
+        __u8 drop_level;
+        __u8 level;
+
+        __le64 generation_v2;
+        __u8 uuid[BTRFS_UUID_SIZE];
+        __u8 parent_uuid[BTRFS_UUID_SIZE];
+        __u8 received_uuid[BTRFS_UUID_SIZE];
+        __le64 ctransid; /* updated when an inode changes */
+        __le64 otransid; /* trans when created */
+        __le64 stransid; /* trans when sent. non-zero for received subvol */
+        __le64 rtransid; /* trans when received. non-zero for received subvol */
+        struct btrfs_timespec ctime;
+        struct btrfs_timespec otime;
+        struct btrfs_timespec stime;
+        struct btrfs_timespec rtime;
+        __le64 reserved[8]; /* for future */
+} __attribute__ ((__packed__));
+
+struct btrfs_root_ref {
+        __le64 dirid;
+        __le64 sequence;
+        __le16 name_len;
+} __attribute__ ((__packed__));
+
+#define BTRFS_QGROUP_LEVEL_SHIFT  48
+
+struct btrfs_qgroup_info_item {
+        __le64 generation;
+        __le64 rfer;
+        __le64 rfer_cmpr;
+        __le64 excl;
+        __le64 excl_cmpr;
+} __attribute__ ((__packed__));
+
+struct btrfs_qgroup_limit_item {
+        __le64 flags;
+        __le64 max_rfer;
+        __le64 max_excl;
+        __le64 rsv_rfer;
+        __le64 rsv_excl;
+} __attribute__ ((__packed__));
+#endif
diff --git a/src/basic/missing_capability.h b/src/basic/missing_capability.h
new file mode 100644 (file)
index 0000000..1308a3d
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/capability.h>
+
+/* 3a101b8de0d39403b2c7e5c23fd0b005668acf48 (3.16) */
+#ifndef CAP_AUDIT_READ
+#define CAP_AUDIT_READ 37
+
+#undef  CAP_LAST_CAP
+#define CAP_LAST_CAP   CAP_AUDIT_READ
+#endif
diff --git a/src/basic/missing_drm.h b/src/basic/missing_drm.h
new file mode 100644 (file)
index 0000000..a64f74e
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#ifndef DRM_IOCTL_SET_MASTER
+#define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
+#endif
+
+#ifndef DRM_IOCTL_DROP_MASTER
+#define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
+#endif
diff --git a/src/basic/missing_ethtool.h b/src/basic/missing_ethtool.h
new file mode 100644 (file)
index 0000000..9ba929c
--- /dev/null
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/types.h>
+
+/* Missing definitions in ethtool.h */
+
+#if !HAVE_ETHTOOL_LINK_MODE_10baseT_Half_BIT /* linux@3f1ac7a700d039c61d8d8b99f28d605d489a60cf (4.6) */
+
+#define ETHTOOL_GLINKSETTINGS   0x0000004c /* Get ethtool_link_settings */
+#define ETHTOOL_SLINKSETTINGS   0x0000004d /* Set ethtool_link_settings */
+
+struct ethtool_link_settings {
+        __u32 cmd;
+        __u32 speed;
+        __u8  duplex;
+        __u8  port;
+        __u8  phy_address;
+        __u8  autoneg;
+        __u8  mdio_support;
+        __u8  eth_tp_mdix;
+        __u8  eth_tp_mdix_ctrl;
+        __s8  link_mode_masks_nwords;
+        __u8  transceiver;
+        __u8  reserved1[3];
+        __u32 reserved[7];
+        __u32 link_mode_masks[0];
+        /* layout of link_mode_masks fields:
+         * __u32 map_supported[link_mode_masks_nwords];
+         * __u32 map_advertising[link_mode_masks_nwords];
+         * __u32 map_lp_advertising[link_mode_masks_nwords];
+         */
+};
+
+enum ethtool_link_mode_bit_indices {
+        ETHTOOL_LINK_MODE_10baseT_Half_BIT           = 0,
+        ETHTOOL_LINK_MODE_10baseT_Full_BIT           = 1,
+        ETHTOOL_LINK_MODE_100baseT_Half_BIT          = 2,
+        ETHTOOL_LINK_MODE_100baseT_Full_BIT          = 3,
+        ETHTOOL_LINK_MODE_1000baseT_Half_BIT         = 4,
+        ETHTOOL_LINK_MODE_1000baseT_Full_BIT         = 5,
+        ETHTOOL_LINK_MODE_Autoneg_BIT                = 6,
+        ETHTOOL_LINK_MODE_TP_BIT                     = 7,
+        ETHTOOL_LINK_MODE_AUI_BIT                    = 8,
+        ETHTOOL_LINK_MODE_MII_BIT                    = 9,
+        ETHTOOL_LINK_MODE_FIBRE_BIT                  = 10,
+        ETHTOOL_LINK_MODE_BNC_BIT                    = 11,
+        ETHTOOL_LINK_MODE_10000baseT_Full_BIT        = 12,
+        ETHTOOL_LINK_MODE_Pause_BIT                  = 13,
+        ETHTOOL_LINK_MODE_Asym_Pause_BIT             = 14,
+        ETHTOOL_LINK_MODE_2500baseX_Full_BIT         = 15,
+        ETHTOOL_LINK_MODE_Backplane_BIT              = 16,
+        ETHTOOL_LINK_MODE_1000baseKX_Full_BIT        = 17,
+        ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT      = 18,
+        ETHTOOL_LINK_MODE_10000baseKR_Full_BIT       = 19,
+        ETHTOOL_LINK_MODE_10000baseR_FEC_BIT         = 20,
+        ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT     = 21,
+        ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT      = 22,
+        ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT      = 23,
+        ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT      = 24,
+        ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT      = 25,
+        ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT      = 26,
+        ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT      = 27,
+        ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT      = 28,
+        ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT      = 29,
+        ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT      = 30,
+        ETHTOOL_LINK_MODE_25000baseCR_Full_BIT       = 31,
+        ETHTOOL_LINK_MODE_25000baseKR_Full_BIT       = 32,
+        ETHTOOL_LINK_MODE_25000baseSR_Full_BIT       = 33,
+        ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT      = 34,
+        ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT      = 35,
+        ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT     = 36,
+        ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT     = 37,
+        ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT     = 38,
+        ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39,
+        ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT      = 40,
+        ETHTOOL_LINK_MODE_1000baseX_Full_BIT         = 41,
+        ETHTOOL_LINK_MODE_10000baseCR_Full_BIT       = 42,
+        ETHTOOL_LINK_MODE_10000baseSR_Full_BIT       = 43,
+        ETHTOOL_LINK_MODE_10000baseLR_Full_BIT       = 44,
+        ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT      = 45,
+        ETHTOOL_LINK_MODE_10000baseER_Full_BIT       = 46,
+        ETHTOOL_LINK_MODE_2500baseT_Full_BIT         = 47,
+        ETHTOOL_LINK_MODE_5000baseT_Full_BIT         = 48,
+
+        ETHTOOL_LINK_MODE_FEC_NONE_BIT               = 49,
+        ETHTOOL_LINK_MODE_FEC_RS_BIT                 = 50,
+        ETHTOOL_LINK_MODE_FEC_BASER_BIT              = 51,
+
+        /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
+         * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
+         * macro for bits > 31. The only way to use indices > 31 is to
+         * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
+         */
+
+        __ETHTOOL_LINK_MODE_LAST
+          = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
+};
+#else
+#if !HAVE_ETHTOOL_LINK_MODE_25000baseCR_Full_BIT /* linux@3851112e4737cd52aaeda0ce8d084be9ee128106 (4.7) */
+#define ETHTOOL_LINK_MODE_25000baseCR_Full_BIT       31
+#define ETHTOOL_LINK_MODE_25000baseKR_Full_BIT       32
+#define ETHTOOL_LINK_MODE_25000baseSR_Full_BIT       33
+#define ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT      34
+#define ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT      35
+#define ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT     36
+#define ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT     37
+#define ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT     38
+#define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
+#endif
+#if !HAVE_ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT /* linux@89da45b8b5b2187734a11038b8593714f964ffd1 (4.8) */
+#define ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT      40
+#endif
+#if !HAVE_ETHTOOL_LINK_MODE_1000baseX_Full_BIT /* linux@5711a98221443aec54c4c81ee98c6ae46acccb65 (4.9) */
+#define ETHTOOL_LINK_MODE_1000baseX_Full_BIT         41
+#define ETHTOOL_LINK_MODE_10000baseCR_Full_BIT       42
+#define ETHTOOL_LINK_MODE_10000baseSR_Full_BIT       43
+#define ETHTOOL_LINK_MODE_10000baseLR_Full_BIT       44
+#define ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT      45
+#define ETHTOOL_LINK_MODE_10000baseER_Full_BIT       46
+#endif
+#if !HAVE_ETHTOOL_LINK_MODE_2500baseT_Full_BIT /* linux@94842b4fc4d6b1691cfc86c6f5251f299d27f4ba (4.10) */
+#define ETHTOOL_LINK_MODE_2500baseT_Full_BIT         47
+#define ETHTOOL_LINK_MODE_5000baseT_Full_BIT         48
+#endif
+#if !HAVE_ETHTOOL_LINK_MODE_FEC_NONE_BIT /* linux@1a5f3da20bd966220931239fbd31e6ac6ff42251 (4.14) */
+#define ETHTOOL_LINK_MODE_FEC_NONE_BIT               49
+#define ETHTOOL_LINK_MODE_FEC_RS_BIT                 50
+#define ETHTOOL_LINK_MODE_FEC_BASER_BIT              51
+#endif
+#endif
diff --git a/src/basic/missing_fcntl.h b/src/basic/missing_fcntl.h
new file mode 100644 (file)
index 0000000..5d1c635
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <fcntl.h>
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
+#endif
+
+#ifndef F_GETPIPE_SZ
+#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+
+#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
+#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
+#define F_SEAL_GROW     0x0004  /* prevent file from growing */
+#define F_SEAL_WRITE    0x0008  /* prevent writes */
+#endif
+
+#ifndef F_OFD_GETLK
+#define F_OFD_GETLK     36
+#define F_OFD_SETLK     37
+#define F_OFD_SETLKW    38
+#endif
+
+#ifndef MAX_HANDLE_SZ
+#define MAX_HANDLE_SZ 128
+#endif
+
+/* The precise definition of __O_TMPFILE is arch specific; use the
+ * values defined by the kernel (note: some are hexa, some are octal,
+ * duplicated as-is from the kernel definitions):
+ * - alpha, parisc, sparc: each has a specific value;
+ * - others: they use the "generic" value.
+ */
+
+#ifndef __O_TMPFILE
+#if defined(__alpha__)
+#define __O_TMPFILE     0100000000
+#elif defined(__parisc__) || defined(__hppa__)
+#define __O_TMPFILE     0400000000
+#elif defined(__sparc__) || defined(__sparc64__)
+#define __O_TMPFILE     0x2000000
+#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
diff --git a/src/basic/missing_fib_rules.h b/src/basic/missing_fib_rules.h
new file mode 100644 (file)
index 0000000..df120d7
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/types.h>
+
+#if !HAVE_FRA_TUN_ID /* linux@e7030878fc8448492b6e5cecd574043f63271298 (4.3) */
+#define FRA_TUN_ID      12
+#endif
+
+#if !HAVE_FRA_SUPPRESS_PREFIXLEN /* linux@6ef94cfafba159d6b1a902ccb3349ac6a34ff6ad, 73f5698e77219bfc3ea1903759fe8e20ab5b285e (3.12) */
+#define FRA_SUPPRESS_IFGROUP 13
+#define FRA_SUPPRESS_PREFIXLEN 14
+#endif
+
+#if !HAVE_FRA_PAD /* linux@b46f6ded906ef0be52a4881ba50a084aeca64d7e (4.7) */
+#define FRA_PAD         18
+#endif
+
+#if !HAVE_FRA_L3MDEV /* linux@96c63fa7393d0a346acfe5a91e0c7d4c7782641b (4.8) */
+#define FRA_L3MDEV      19
+#endif
+
+#if !HAVE_FRA_UID_RANGE /* linux@622ec2c9d52405973c9f1ca5116eb1c393adfc7d (4.10) */
+#define FRA_UID_RANGE   20
+
+struct fib_rule_uid_range {
+        __u32 start;
+        __u32 end;
+};
+#endif
+
+#if !HAVE_FRA_DPORT_RANGE /* linux@1b71af6053af1bd2f849e9fda4f71c1e3f145dcf, bfff4862653bb96001ab57c1edd6d03f48e5f035 (4.17) */
+#define FRA_PROTOCOL    21
+#define FRA_IP_PROTO    22
+#define FRA_SPORT_RANGE 23
+#define FRA_DPORT_RANGE 24
+
+#undef  FRA_MAX
+#define FRA_MAX         24
+
+struct fib_rule_port_range {
+        __u16 start;
+        __u16 end;
+};
+#endif
diff --git a/src/basic/missing_fou.h b/src/basic/missing_fou.h
new file mode 100644 (file)
index 0000000..d8c7435
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !HAVE_LINUX_FOU_H /* linux@23461551c00628c3f3fe9cf837bf53cf8f212b63 (3.18) */
+
+#define FOU_GENL_NAME           "fou"
+#define FOU_GENL_VERSION        0x1
+
+enum {
+        FOU_ATTR_UNSPEC,
+        FOU_ATTR_PORT,                  /* u16 */
+        FOU_ATTR_AF,                    /* u8 */
+        FOU_ATTR_IPPROTO,               /* u8 */
+        FOU_ATTR_TYPE,                  /* u8 */
+        FOU_ATTR_REMCSUM_NOPARTIAL,     /* flag */
+
+        __FOU_ATTR_MAX,
+};
+
+#define FOU_ATTR_MAX                (__FOU_ATTR_MAX - 1)
+
+enum {
+        FOU_CMD_UNSPEC,
+        FOU_CMD_ADD,
+        FOU_CMD_DEL,
+        FOU_CMD_GET,
+
+        __FOU_CMD_MAX,
+};
+
+enum {
+        FOU_ENCAP_UNSPEC,
+        FOU_ENCAP_DIRECT,
+        FOU_ENCAP_GUE,
+};
+
+#define FOU_CMD_MAX        (__FOU_CMD_MAX - 1)
+
+#else
+
+#if !HAVE_FOU_ATTR_REMCSUM_NOPARTIAL /* linux@fe881ef11cf0220f118816181930494d484c4883 (4.0) */
+#define FOU_ATTR_REMCSUM_NOPARTIAL 5
+
+#undef  FOU_ATTR_MAX
+#define FOU_ATTR_MAX               5
+#endif
+
+#if !HAVE_FOU_CMD_GET /* linux@7a6c8c34e5b71ac50e39588e20b39494a9e1d8e5 (4.1) */
+#define FOU_CMD_GET 3
+
+#undef  FOU_CMD_MAX
+#define FOU_CMD_MAX 3
+#endif
+
+#endif
diff --git a/src/basic/missing_fs.h b/src/basic/missing_fs.h
new file mode 100644 (file)
index 0000000..48c1af0
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+/* linux/fs.h */
+#ifndef RENAME_NOREPLACE /* 0a7c3937a1f23f8cb5fc77ae01661e9968a51d0c (3.15) */
+#define RENAME_NOREPLACE (1 << 0)
+#endif
+
+/* linux/fs.h or sys/mount.h */
+#ifndef MS_MOVE
+#define MS_MOVE 8192
+#endif
+
+#ifndef MS_REC
+#define MS_REC 16384
+#endif
+
+#ifndef MS_PRIVATE
+#define MS_PRIVATE      (1<<18)
+#endif
+
+#ifndef MS_SLAVE
+#define MS_SLAVE        (1<<19)
+#endif
+
+#ifndef MS_SHARED
+#define MS_SHARED       (1<<20)
+#endif
+
+#ifndef MS_RELATIME
+#define MS_RELATIME     (1<<21)
+#endif
+
+#ifndef MS_KERNMOUNT
+#define MS_KERNMOUNT    (1<<22)
+#endif
+
+#ifndef MS_I_VERSION
+#define MS_I_VERSION    (1<<23)
+#endif
+
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME  (1<<24)
+#endif
+
+#ifndef MS_LAZYTIME
+#define MS_LAZYTIME     (1<<25)
+#endif
+
+/* Not exposed yet. Defined at fs/ext4/ext4.h */
+#ifndef EXT4_IOC_RESIZE_FS
+#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+#endif
+
+/* Not exposed yet. Defined at fs/cifs/cifsglob.h */
+#ifndef CIFS_MAGIC_NUMBER
+#define CIFS_MAGIC_NUMBER 0xFF534D42
+#endif
+
+/* linux/nsfs.h */
+#ifndef NS_GET_NSTYPE /* d95fa3c76a66b6d76b1e109ea505c55e66360f3c (4.11) */
+#define NS_GET_NSTYPE _IO(0xb7, 0x3)
+#endif
diff --git a/src/basic/missing_if_bridge.h b/src/basic/missing_if_bridge.h
new file mode 100644 (file)
index 0000000..9306062
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !HAVE_IFLA_BRIDGE_VLAN_TUNNEL_INFO /* linux@b3c7ef0adadc5768e0baa786213c6bd1ce521a77 (4.11) */
+#define IFLA_BRIDGE_VLAN_TUNNEL_INFO 3
+
+#undef  IFLA_BRIDGE_MAX
+#define IFLA_BRIDGE_MAX              3
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_RANGE_END
+#define BRIDGE_VLAN_INFO_RANGE_END   (1<<4) /* VLAN is end of vlan range */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_BRENTRY
+#define BRIDGE_VLAN_INFO_BRENTRY     (1<<5) /* Global bridge VLAN entry */
+#endif
diff --git a/src/basic/missing_if_link.h b/src/basic/missing_if_link.h
new file mode 100644 (file)
index 0000000..0767542
--- /dev/null
@@ -0,0 +1,390 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !HAVE_IFLA_INET6_ADDR_GEN_MODE /* linux@bc91b0f07ada5535427373a4e2050877bcc12218 (3.17) */
+#define IFLA_INET6_ADDR_GEN_MODE 8
+
+#undef  IFLA_INET6_MAX
+#define IFLA_INET6_MAX           8
+
+enum in6_addr_gen_mode {
+        IN6_ADDR_GEN_MODE_EUI64,
+        IN6_ADDR_GEN_MODE_NONE,
+        IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
+        IN6_ADDR_GEN_MODE_RANDOM,
+};
+#else
+#if !HAVE_IN6_ADDR_GEN_MODE_STABLE_PRIVACY /* linux@622c81d57b392cc9be836670eb464a4dfaa9adfe (4.1) */
+#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2
+#endif
+#if !HAVE_IN6_ADDR_GEN_MODE_RANDOM /* linux@cc9da6cc4f56e05cc9e591459fe0192727ff58b3 (4.5) */
+#define IN6_ADDR_GEN_MODE_RANDOM         3
+#endif
+#endif /* !HAVE_IFLA_INET6_ADDR_GEN_MODE */
+
+#if !HAVE_IFLA_IPVLAN_MODE /* linux@2ad7bf3638411cb547f2823df08166c13ab04269 (3.19) */
+enum {
+        IFLA_IPVLAN_UNSPEC,
+        IFLA_IPVLAN_MODE,
+        IFLA_IPVLAN_FLAGS,
+        __IFLA_IPVLAN_MAX
+};
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+enum ipvlan_mode {
+        IPVLAN_MODE_L2 = 0,
+        IPVLAN_MODE_L3,
+        IPVLAN_MODE_L3S,
+        IPVLAN_MODE_MAX
+};
+#else
+#if !HAVE_IPVLAN_MODE_L3S /* linux@4fbae7d83c98c30efcf0a2a2ac55fbb75ef5a1a5 (4.9) */
+#define IPVLAN_MODE_L3S   2
+#define IPVLAN_MODE_MAX   3
+#endif
+#if !HAVE_IFLA_IPVLAN_FLAGS /* linux@a190d04db93710ae166749055b6985397c6d13f5 (4.15) */
+#define IFLA_IPVLAN_FLAGS 2
+
+#undef  IFLA_IPVLAN_MAX
+#define IFLA_IPVLAN_MAX   2
+#endif
+#endif /* !HAVE_IFLA_IPVLAN_MODE */
+
+/* linux@a190d04db93710ae166749055b6985397c6d13f5 (4.15) */
+#ifndef IPVLAN_F_PRIVATE
+#define IPVLAN_F_PRIVATE 0x01
+#endif
+
+/* linux@fe89aa6b250c1011ccf425fbb7998e96bd54263f (4.15) */
+#ifndef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA    0x02
+#endif
+
+#if !HAVE_IFLA_PHYS_PORT_ID /* linux@66cae9ed6bc46b8cc57a9693f99f69926f3cc7ef (3.12) */
+#define IFLA_PHYS_PORT_ID       34
+#endif
+#if !HAVE_IFLA_CARRIER_CHANGES /* linux@2d3b479df41a10e2f41f9259fcba775bd34de6e4 (3.15) */
+#define IFLA_CARRIER_CHANGES    35
+#endif
+#if !HAVE_IFLA_PHYS_SWITCH_ID /* linux@82f2841291cfaf4d225aa1766424280254d3e3b2 (3.19) */
+#define IFLA_PHYS_SWITCH_ID     36
+#endif
+#if !HAVE_IFLA_LINK_NETNSID /* linux@d37512a277dfb2cef8a578e25a3246f61399a55a (4.0) */
+#define IFLA_LINK_NETNSID       37
+#endif
+#if !HAVE_IFLA_PHYS_PORT_NAME /* linux@db24a9044ee191c397dcd1c6574f56d67d7c8df5 (4.1) */
+#define IFLA_PHYS_PORT_NAME     38
+#endif
+#if !HAVE_IFLA_PROTO_DOWN /* linux@88d6378bd6c096cb8440face3ae3f33d55a2e6e4 (4.3) */
+#define IFLA_PROTO_DOWN         39
+#endif
+#if !HAVE_IFLA_GSO_MAX_SIZE /* linux@c70ce028e834f8e51306217dbdbd441d851c64d3 (4.6) */
+#define IFLA_GSO_MAX_SEGS       40
+#define IFLA_GSO_MAX_SIZE       41
+#endif
+#if !HAVE_IFLA_PAD /* linux@18402843bf88c2e9674e1a3a05c73b7d9b09ee05 (4.7) */
+#define IFLA_PAD                42
+#endif
+#if !HAVE_IFLA_XDP /* linux@d1fdd9138682e0f272beee0cb08b6328c5478b26 (4.8) */
+#define IFLA_XDP                43
+#endif
+#if !HAVE_IFLA_EVENT /* linux@3d3ea5af5c0b382bc9d9aed378fd814fb5d4a011 (4.13) */
+#define IFLA_EVENT              44
+#endif
+#if !HAVE_IFLA_IF_NETNSID /* linux@6621dd29eb9b5e6774ec7a9a75161352fdea47fc, 79e1ad148c844f5c8b9d76b36b26e3886dca95ae (4.15) */
+#define IFLA_IF_NETNSID         45
+#define IFLA_NEW_NETNSID        46
+#endif
+#if !HAVE_IFLA_TARGET_NETNSID /* linux@19d8f1ad12fd746e60707a58d954980013c7a35a (4.20) */
+#define IFLA_TARGET_NETNSID IFLA_IF_NETNSID
+#endif
+#if !HAVE_IFLA_NEW_IFINDEX /* linux@b2d3bcfa26a7a8de41f358a6cae8b848673b3c6e, 38e01b30563a5b5ade7b54e5d739d16a2b02fe82 (4.16) */
+#define IFLA_CARRIER_UP_COUNT   47
+#define IFLA_CARRIER_DOWN_COUNT 48
+#define IFLA_NEW_IFINDEX        49
+#endif
+#if !HAVE_IFLA_MAX_MTU /* linux@3e7a50ceb11ea75c27e944f1a01e478fd62a2d8d (4.19) */
+#define IFLA_MIN_MTU            50
+#define IFLA_MAX_MTU            51
+
+#undef  IFLA_MAX
+#define IFLA_MAX                51
+#endif
+
+#if !HAVE_IFLA_BOND_ACTIVE_SLAVE /* linux@ec76aa49855f6d6fea5e01de179fb57dd47c619d (3.13) */
+#define IFLA_BOND_ACTIVE_SLAVE      2
+#endif
+#if !HAVE_IFLA_BOND_AD_INFO /* linux@4ee7ac7526d4a9413cafa733d824edfe49fdcc46 (3.14) */
+#define IFLA_BOND_MIIMON            3
+#define IFLA_BOND_UPDELAY           4
+#define IFLA_BOND_DOWNDELAY         5
+#define IFLA_BOND_USE_CARRIER       6
+#define IFLA_BOND_ARP_INTERVAL      7
+#define IFLA_BOND_ARP_IP_TARGET     8
+#define IFLA_BOND_ARP_VALIDATE      9
+#define IFLA_BOND_ARP_ALL_TARGETS   10
+#define IFLA_BOND_PRIMARY           11
+#define IFLA_BOND_PRIMARY_RESELECT  12
+#define IFLA_BOND_FAIL_OVER_MAC     13
+#define IFLA_BOND_XMIT_HASH_POLICY  14
+#define IFLA_BOND_RESEND_IGMP       15
+#define IFLA_BOND_NUM_PEER_NOTIF    16
+#define IFLA_BOND_ALL_SLAVES_ACTIVE 17
+#define IFLA_BOND_MIN_LINKS         18
+#define IFLA_BOND_LP_INTERVAL       19
+#define IFLA_BOND_PACKETS_PER_SLAVE 20
+#define IFLA_BOND_AD_LACP_RATE      21
+#define IFLA_BOND_AD_SELECT         22
+#define IFLA_BOND_AD_INFO           23
+#endif
+#if !HAVE_IFLA_BOND_AD_ACTOR_SYSTEM /* linux@171a42c38c6e1a5a076d6276e94e55a0b5b7868c (4.2) */
+#define IFLA_BOND_AD_ACTOR_SYS_PRIO 24
+#define IFLA_BOND_AD_USER_PORT_KEY  25
+#define IFLA_BOND_AD_ACTOR_SYSTEM   26
+#endif
+#if !HAVE_IFLA_BOND_TLB_DYNAMIC_LB /* linux@0f7bffd9e512b77279bbce704fad3cb1d6887958 (4.3) */
+#define IFLA_BOND_TLB_DYNAMIC_LB    27
+
+#undef  IFLA_BOND_MAX
+#define IFLA_BOND_MAX               27
+#endif
+
+#if !HAVE_IFLA_VXLAN_UDP_ZERO_CSUM6_RX /* linux@359a0ea9875ef4f32c8425bbe1ae348e1fd2ed2a (3.16) */
+#define IFLA_VXLAN_UDP_CSUM          18
+#define IFLA_VXLAN_UDP_ZERO_CSUM6_TX 19
+#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX 20
+#endif
+#if !HAVE_IFLA_VXLAN_REMCSUM_NOPARTIAL /* linux@dfd8645ea1bd91277f841e74c33e1f4dbbede808..0ace2ca89cbd6bcdf2b9d2df1fa0fa24ea9d1653 (4.0) */
+#define IFLA_VXLAN_REMCSUM_TX        21
+#define IFLA_VXLAN_REMCSUM_RX        22
+#define IFLA_VXLAN_GBP               23
+#define IFLA_VXLAN_REMCSUM_NOPARTIAL 24
+#endif
+#if !HAVE_IFLA_VXLAN_COLLECT_METADATA /* linux@f8a9b1bc1b238eed9987da747a0e52f5bb009980 (4.3) */
+#define IFLA_VXLAN_COLLECT_METADATA  25
+#endif
+#if !HAVE_IFLA_VXLAN_LABEL /* linux@e7f70af111f086a20800ad2e17f544b2e3e0f375 (4.6) */
+#define IFLA_VXLAN_LABEL             26
+#endif
+#if !HAVE_IFLA_VXLAN_GPE /* linux@e1e5314de08ba6003b358125eafc9ad9e75a950c (4.7) */
+#define IFLA_VXLAN_GPE               27
+#endif
+#if !HAVE_IFLA_VXLAN_TTL_INHERIT /* linux@72f6d71e491e6ce269b564865b21fab0a4402dd3 (4.18) */
+#define IFLA_VXLAN_TTL_INHERIT       28
+
+#undef  IFLA_VXLAN_MAX
+#define IFLA_VXLAN_MAX               28
+#endif
+
+#if !HAVE_IFLA_GENEVE_TOS /* linux@2d07dc79fe04a43d82a346ced6bbf07bdb523f1b..d89511251f6519599b109dc6cda87a6ab314ed8c (4.2) */
+enum {
+        IFLA_GENEVE_UNSPEC,
+        IFLA_GENEVE_ID,
+        IFLA_GENEVE_REMOTE,
+        IFLA_GENEVE_TTL,
+        IFLA_GENEVE_TOS,
+        IFLA_GENEVE_PORT,        /* destination port */
+        IFLA_GENEVE_COLLECT_METADATA,
+        IFLA_GENEVE_REMOTE6,
+        IFLA_GENEVE_UDP_CSUM,
+        IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+        IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+        IFLA_GENEVE_LABEL,
+        IFLA_GENEVE_TTL_INHERIT,
+        __IFLA_GENEVE_MAX
+};
+#define IFLA_GENEVE_MAX        (__IFLA_GENEVE_MAX - 1)
+#else
+#if !HAVE_IFLA_GENEVE_COLLECT_METADATA /* linux@e305ac6cf5a1e1386aedce7ef9cb773635d5845c (4.3) */
+#define IFLA_GENEVE_PORT              5
+#define IFLA_GENEVE_COLLECT_METADATA  6
+#endif
+#if !HAVE_IFLA_GENEVE_REMOTE6 /* linux@8ed66f0e8235118a31720acdab3bbbe9debd0f6a (4.4) */
+#define IFLA_GENEVE_REMOTE6           7
+#endif
+#if !HAVE_IFLA_GENEVE_UDP_ZERO_CSUM6_RX /* linux@abe492b4f50c3ae2ebcfaa2f5c16176aebaa1c68 (4.5) */
+#define IFLA_GENEVE_UDP_CSUM          8
+#define IFLA_GENEVE_UDP_ZERO_CSUM6_TX 9
+#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
+#endif
+#if !HAVE_IFLA_GENEVE_LABEL /* linux@8eb3b99554b82da968d1fbc00df9f3156c5e2d63 (4.6) */
+#define IFLA_GENEVE_LABEL             11
+#endif
+#if !HAVE_IFLA_GENEVE_TTL_INHERIT /* linux@52d0d404d39dd9eac71a181615d6ca15e23d8e38 (4.20) */
+#define IFLA_GENEVE_TTL_INHERIT       12
+
+#undef  IFLA_GENEVE_MAX
+#define IFLA_GENEVE_MAX               12
+#endif
+#endif
+
+#if !HAVE_IFLA_BR_MAX_AGE /* linux@e5c3ea5c668033b303e7ac835d7d91da32d97958 (3.18) */
+enum {
+        IFLA_BR_UNSPEC,
+        IFLA_BR_FORWARD_DELAY,
+        IFLA_BR_HELLO_TIME,
+        IFLA_BR_MAX_AGE,
+        IFLA_BR_AGEING_TIME,
+        IFLA_BR_STP_STATE,
+        IFLA_BR_PRIORITY,
+        IFLA_BR_VLAN_FILTERING,
+        IFLA_BR_VLAN_PROTOCOL,
+        IFLA_BR_GROUP_FWD_MASK,
+        IFLA_BR_ROOT_ID,
+        IFLA_BR_BRIDGE_ID,
+        IFLA_BR_ROOT_PORT,
+        IFLA_BR_ROOT_PATH_COST,
+        IFLA_BR_TOPOLOGY_CHANGE,
+        IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+        IFLA_BR_HELLO_TIMER,
+        IFLA_BR_TCN_TIMER,
+        IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+        IFLA_BR_GC_TIMER,
+        IFLA_BR_GROUP_ADDR,
+        IFLA_BR_FDB_FLUSH,
+        IFLA_BR_MCAST_ROUTER,
+        IFLA_BR_MCAST_SNOOPING,
+        IFLA_BR_MCAST_QUERY_USE_IFADDR,
+        IFLA_BR_MCAST_QUERIER,
+        IFLA_BR_MCAST_HASH_ELASTICITY,
+        IFLA_BR_MCAST_HASH_MAX,
+        IFLA_BR_MCAST_LAST_MEMBER_CNT,
+        IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+        IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+        IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+        IFLA_BR_MCAST_QUERIER_INTVL,
+        IFLA_BR_MCAST_QUERY_INTVL,
+        IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+        IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+        IFLA_BR_NF_CALL_IPTABLES,
+        IFLA_BR_NF_CALL_IP6TABLES,
+        IFLA_BR_NF_CALL_ARPTABLES,
+        IFLA_BR_VLAN_DEFAULT_PVID,
+        IFLA_BR_PAD,
+        IFLA_BR_VLAN_STATS_ENABLED,
+        IFLA_BR_MCAST_STATS_ENABLED,
+        IFLA_BR_MCAST_IGMP_VERSION,
+        IFLA_BR_MCAST_MLD_VERSION,
+        IFLA_BR_VLAN_STATS_PER_PORT,
+        __IFLA_BR_MAX,
+};
+
+#define IFLA_BR_MAX        (__IFLA_BR_MAX - 1)
+#else
+#if !HAVE_IFLA_BR_PRIORITY /* linux@af615762e972be0c66cf1d156ca4fac13b93c0b0 (4.1) */
+#define IFLA_BR_AGEING_TIME                4
+#define IFLA_BR_STP_STATE                  5
+#define IFLA_BR_PRIORITY                   6
+#endif
+#if !HAVE_IFLA_BR_VLAN_PROTOCOL /* linux@a7854037da006a7472c48773e3190db55217ec9b, d2d427b3927bd7a0348fc7f323d0e291f79a2779 (4.3) */
+#define IFLA_BR_VLAN_FILTERING             7
+#define IFLA_BR_VLAN_PROTOCOL              8
+#endif
+#if !HAVE_IFLA_BR_VLAN_DEFAULT_PVID /* linux@7910228b6bb35f3c8e0bc72a8d84c29616cb1b90..0f963b7592ef9e054974b6672b86ec1edd84b4bc (4.4) */
+#define IFLA_BR_GROUP_FWD_MASK             9
+#define IFLA_BR_ROOT_ID                    10
+#define IFLA_BR_BRIDGE_ID                  11
+#define IFLA_BR_ROOT_PORT                  12
+#define IFLA_BR_ROOT_PATH_COST             13
+#define IFLA_BR_TOPOLOGY_CHANGE            14
+#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED   15
+#define IFLA_BR_HELLO_TIMER                16
+#define IFLA_BR_TCN_TIMER                  17
+#define IFLA_BR_TOPOLOGY_CHANGE_TIMER      18
+#define IFLA_BR_GC_TIMER                   19
+#define IFLA_BR_GROUP_ADDR                 20
+#define IFLA_BR_FDB_FLUSH                  21
+#define IFLA_BR_MCAST_ROUTER               22
+#define IFLA_BR_MCAST_SNOOPING             23
+#define IFLA_BR_MCAST_QUERY_USE_IFADDR     24
+#define IFLA_BR_MCAST_QUERIER              25
+#define IFLA_BR_MCAST_HASH_ELASTICITY      26
+#define IFLA_BR_MCAST_HASH_MAX             27
+#define IFLA_BR_MCAST_LAST_MEMBER_CNT      28
+#define IFLA_BR_MCAST_STARTUP_QUERY_CNT    29
+#define IFLA_BR_MCAST_LAST_MEMBER_INTVL    30
+#define IFLA_BR_MCAST_MEMBERSHIP_INTVL     31
+#define IFLA_BR_MCAST_QUERIER_INTVL        32
+#define IFLA_BR_MCAST_QUERY_INTVL          33
+#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34
+#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL  35
+#define IFLA_BR_NF_CALL_IPTABLES           36
+#define IFLA_BR_NF_CALL_IP6TABLES          37
+#define IFLA_BR_NF_CALL_ARPTABLES          38
+#define IFLA_BR_VLAN_DEFAULT_PVID          39
+#endif
+#if !HAVE_IFLA_BR_VLAN_STATS_ENABLED /* linux@12a0faa3bd76157b9dc096758d6818ff535e4586, 6dada9b10a0818ba72c249526a742c8c41274a73 (4.7) */
+#define IFLA_BR_PAD                        40
+#define IFLA_BR_VLAN_STATS_ENABLED         41
+#endif
+#if !HAVE_IFLA_BR_MCAST_STATS_ENABLED /* linux@1080ab95e3c7bdd77870e209aff83c763fdcf439 (4.8) */
+#define IFLA_BR_MCAST_STATS_ENABLED        42
+#endif
+#if !HAVE_IFLA_BR_MCAST_MLD_VERSION /* linux@5e9235853d652a295d5f56cb8652950b6b5bf56b, aa2ae3e71c74cc00ec22f133dc900b3817415785 (4.10) */
+#define IFLA_BR_MCAST_IGMP_VERSION         43
+#define IFLA_BR_MCAST_MLD_VERSION          44
+#endif
+#if !HAVE_IFLA_BR_VLAN_STATS_PER_PORT /* linux@9163a0fc1f0c0980f117cc25f4fa6ba9b0750a36 (4.20) */
+#define IFLA_BR_VLAN_STATS_PER_PORT        45
+
+#undef  IFLA_BR_MAX
+#define IFLA_BR_MAX                        45
+#endif
+#endif
+
+#if !HAVE_IFLA_BRPORT_LEARNING_SYNC /* linux@958501163ddd6ea22a98f94fa0e7ce6d4734e5c4, efacacdaf7cb5a0592ed772e3731636b2742e34a (3.19)*/
+#define IFLA_BRPORT_PROXYARP            10
+#define IFLA_BRPORT_LEARNING_SYNC       11
+#endif
+#if !HAVE_IFLA_BRPORT_PROXYARP_WIFI /* linux@842a9ae08a25671db3d4f689eed68b4d64be15b5 (4.1) */
+#define IFLA_BRPORT_PROXYARP_WIFI       12
+#endif
+#if !HAVE_IFLA_BRPORT_MULTICAST_ROUTER /* linux@4ebc7660ab4559cad10b6595e05f70562bb26dc5..5d6ae479ab7ddf77bb22bdf739268581453ff886 (4.4) */
+#define IFLA_BRPORT_ROOT_ID             13
+#define IFLA_BRPORT_BRIDGE_ID           14
+#define IFLA_BRPORT_DESIGNATED_PORT     15
+#define IFLA_BRPORT_DESIGNATED_COST     16
+#define IFLA_BRPORT_ID                  17
+#define IFLA_BRPORT_NO                  18
+#define IFLA_BRPORT_TOPOLOGY_CHANGE_ACK 19
+#define IFLA_BRPORT_CONFIG_PENDING      20
+#define IFLA_BRPORT_MESSAGE_AGE_TIMER   21
+#define IFLA_BRPORT_FORWARD_DELAY_TIMER 22
+#define IFLA_BRPORT_HOLD_TIMER          23
+#define IFLA_BRPORT_FLUSH               24
+#define IFLA_BRPORT_MULTICAST_ROUTER    25
+#endif
+#if !HAVE_IFLA_BRPORT_PAD /* linux@12a0faa3bd76157b9dc096758d6818ff535e4586 (4.7) */
+#define IFLA_BRPORT_PAD                 26
+#endif
+#if !HAVE_IFLA_BRPORT_MCAST_FLOOD /* linux@b6cb5ac8331b6bcfe9ce38c7f7f58db6e1d6270a (4.9) */
+#define IFLA_BRPORT_MCAST_FLOOD         27
+#endif
+#if !HAVE_IFLA_BRPORT_VLAN_TUNNEL /* linux@6db6f0eae6052b70885562e1733896647ec1d807, b3c7ef0adadc5768e0baa786213c6bd1ce521a77 (4.11) */
+#define IFLA_BRPORT_MCAST_TO_UCAST      28
+#define IFLA_BRPORT_VLAN_TUNNEL         29
+#endif
+#if !HAVE_IFLA_BRPORT_BCAST_FLOOD /* linux@99f906e9ad7b6e79ffeda30f45906a8448b9d6a2 (4.12) */
+#define IFLA_BRPORT_BCAST_FLOOD         30
+#endif
+#if !HAVE_IFLA_BRPORT_NEIGH_SUPPRESS /* linux@5af48b59f35cf712793badabe1a574a0d0ce3bd3, 821f1b21cabb46827ce39ddf82e2789680b5042a (4.15) */
+#define IFLA_BRPORT_GROUP_FWD_MASK      31
+#define IFLA_BRPORT_NEIGH_SUPPRESS      32
+#endif
+#if !HAVE_IFLA_BRPORT_ISOLATED /* linux@7d850abd5f4edb1b1ca4b4141a4453305736f564 (4.18) */
+#define IFLA_BRPORT_ISOLATED            33
+#endif
+#if !HAVE_IFLA_BRPORT_BACKUP_PORT /* linux@2756f68c314917d03eb348084edb08bb929139d9 (4.19) */
+#define IFLA_BRPORT_BACKUP_PORT         34
+
+#undef  IFLA_BRPORT_MAX
+#define IFLA_BRPORT_MAX                 34
+#endif
+
+#if !HAVE_IFLA_VRF_TABLE /* linux@4e3c89920cd3a6cfce22c6f537690747c26128dd (4.3) */
+enum {
+        IFLA_VRF_UNSPEC,
+        IFLA_VRF_TABLE,
+        __IFLA_VRF_MAX
+};
+#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1)
+#endif
diff --git a/src/basic/missing_if_tunnel.h b/src/basic/missing_if_tunnel.h
new file mode 100644 (file)
index 0000000..f51fdd1
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !HAVE_IFLA_VTI_FWMARK /* linux@0a473b82cb23e7a35c4be6e9765c8487a65e8f55 (4.12) */
+#define IFLA_VTI_FWMARK 6
+
+#undef  IFLA_VTI_MAX
+#define IFLA_VTI_MAX    6
+#endif
+
+#if !HAVE_IFLA_IPTUN_ENCAP_DPORT /* linux@56328486539ddd07cbaafec7a542a2c8a3043623 (3.18)*/
+#define IFLA_IPTUN_ENCAP_TYPE       15
+#define IFLA_IPTUN_ENCAP_FLAGS      16
+#define IFLA_IPTUN_ENCAP_SPORT      17
+#define IFLA_IPTUN_ENCAP_DPORT      18
+#endif
+
+#if !HAVE_IFLA_IPTUN_COLLECT_METADATA /* linux@cfc7381b3002756b1dcada32979e942aa3126e31 (4.9) */
+#define IFLA_IPTUN_COLLECT_METADATA 19
+#endif
+
+#if !HAVE_IFLA_IPTUN_FWMARK /* linux@0a473b82cb23e7a35c4be6e9765c8487a65e8f55 (4.12) */
+#define IFLA_IPTUN_FWMARK           20
+
+#undef  IFLA_IPTUN_MAX
+#define IFLA_IPTUN_MAX              20
+#endif
+
+#if !HAVE_IFLA_GRE_ENCAP_DPORT /* linux@4565e9919cda747815547e2e5d7b78f15efbffdf (3.18) */
+#define IFLA_GRE_ENCAP_TYPE       14
+#define IFLA_GRE_ENCAP_FLAGS      15
+#define IFLA_GRE_ENCAP_SPORT      16
+#define IFLA_GRE_ENCAP_DPORT      17
+#endif
+
+#if !HAVE_IFLA_GRE_COLLECT_METADATA /* linux@2e15ea390e6f4466655066d97e22ec66870a042c (4.3) */
+#define IFLA_GRE_COLLECT_METADATA 18
+#endif
+
+#if !HAVE_IFLA_GRE_IGNORE_DF /* linux@22a59be8b7693eb2d0897a9638f5991f2f8e4ddd (4.8) */
+#define IFLA_GRE_IGNORE_DF        19
+#endif
+
+#if !HAVE_IFLA_GRE_FWMARK /* linux@0a473b82cb23e7a35c4be6e9765c8487a65e8f55 (4.12) */
+#define IFLA_GRE_FWMARK           20
+#endif
+
+#if !HAVE_IFLA_GRE_ERSPAN_INDEX /* linux@84e54fe0a5eaed696dee4019c396f8396f5a908b (4.14) */
+#define IFLA_GRE_ERSPAN_INDEX     21
+#endif
+
+#if !HAVE_IFLA_GRE_ERSPAN_HWID /* linux@f551c91de262ba36b20c3ac19538afb4f4507441 (4.16) */
+#define IFLA_GRE_ERSPAN_VER       22
+#define IFLA_GRE_ERSPAN_DIR       23
+#define IFLA_GRE_ERSPAN_HWID      24
+
+#undef  IFLA_GRE_MAX
+#define IFLA_GRE_MAX              24
+#endif
diff --git a/src/basic/missing_input.h b/src/basic/missing_input.h
new file mode 100644 (file)
index 0000000..b91ccb6
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+/* linux@c7dc65737c9a607d3e6f8478659876074ad129b8 (3.12) */
+#ifndef EVIOCREVOKE
+#define EVIOCREVOKE _IOW('E', 0x91, int)
+#endif
+
+/* linux@06a16293f71927f756dcf37558a79c0b05a91641 (4.4) */
+#ifndef EVIOCSMASK
+struct input_mask {
+        __u32 type;
+        __u32 codes_size;
+        __u64 codes_ptr;
+};
+
+#define EVIOCGMASK _IOR('E', 0x92, struct input_mask)
+#define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
+#endif
+
+/* linux@7611392fe8ff95ecae528b01a815ae3d72ca6b95 (3.17) */
+#ifndef INPUT_PROP_POINTING_STICK
+#define INPUT_PROP_POINTING_STICK 0x05
+#endif
+
+/* linux@500d4160abe9a2e88b12e319c13ae3ebd1e18108 (4.0) */
+#ifndef INPUT_PROP_ACCELEROMETER
+#define INPUT_PROP_ACCELEROMETER  0x06
+#endif
+
+/* linux@d09bbfd2a8408a995419dff0d2ba906013cf4cc9 (3.11) */
+#ifndef BTN_DPAD_UP
+#define BTN_DPAD_UP    0x220
+#define BTN_DPAD_DOWN  0x221
+#define BTN_DPAD_LEFT  0x222
+#define BTN_DPAD_RIGHT 0x223
+#endif
+
+/* linux@358f24704f2f016af7d504b357cdf32606091d07 (3.13) */
+#ifndef KEY_ALS_TOGGLE
+#define KEY_ALS_TOGGLE 0x230
+#endif
diff --git a/src/basic/missing_keyctl.h b/src/basic/missing_keyctl.h
new file mode 100644 (file)
index 0000000..7eb7095
--- /dev/null
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/keyctl.h>
+
+#ifndef KEYCTL_JOIN_SESSION_KEYRING
+#define KEYCTL_JOIN_SESSION_KEYRING 1
+#endif
+
+#ifndef KEYCTL_CHOWN
+#define KEYCTL_CHOWN 4
+#endif
+
+#ifndef KEYCTL_SETPERM
+#define KEYCTL_SETPERM 5
+#endif
+
+#ifndef KEYCTL_DESCRIBE
+#define KEYCTL_DESCRIBE 6
+#endif
+
+#ifndef KEYCTL_LINK
+#define KEYCTL_LINK 8
+#endif
+
+#ifndef KEYCTL_READ
+#define KEYCTL_READ 11
+#endif
+
+#ifndef KEYCTL_SET_TIMEOUT
+#define KEYCTL_SET_TIMEOUT 15
+#endif
+
+#ifndef KEY_SPEC_USER_KEYRING
+#define KEY_SPEC_USER_KEYRING -4
+#endif
+
+#ifndef KEY_SPEC_SESSION_KEYRING
+#define KEY_SPEC_SESSION_KEYRING -3
+#endif
+
+/* From linux/key.h */
+#ifndef KEY_POS_VIEW
+
+typedef int32_t key_serial_t;
+
+#define KEY_POS_VIEW    0x01000000
+#define KEY_POS_READ    0x02000000
+#define KEY_POS_WRITE   0x04000000
+#define KEY_POS_SEARCH  0x08000000
+#define KEY_POS_LINK    0x10000000
+#define KEY_POS_SETATTR 0x20000000
+#define KEY_POS_ALL     0x3f000000
+
+#define KEY_USR_VIEW    0x00010000
+#define KEY_USR_READ    0x00020000
+#define KEY_USR_WRITE   0x00040000
+#define KEY_USR_SEARCH  0x00080000
+#define KEY_USR_LINK    0x00100000
+#define KEY_USR_SETATTR 0x00200000
+#define KEY_USR_ALL     0x003f0000
+
+#define KEY_GRP_VIEW    0x00000100
+#define KEY_GRP_READ    0x00000200
+#define KEY_GRP_WRITE   0x00000400
+#define KEY_GRP_SEARCH  0x00000800
+#define KEY_GRP_LINK    0x00001000
+#define KEY_GRP_SETATTR 0x00002000
+#define KEY_GRP_ALL     0x00003f00
+
+#define KEY_OTH_VIEW    0x00000001
+#define KEY_OTH_READ    0x00000002
+#define KEY_OTH_WRITE   0x00000004
+#define KEY_OTH_SEARCH  0x00000008
+#define KEY_OTH_LINK    0x00000010
+#define KEY_OTH_SETATTR 0x00000020
+#define KEY_OTH_ALL     0x0000003f
+#endif
diff --git a/src/basic/missing_magic.h b/src/basic/missing_magic.h
new file mode 100644 (file)
index 0000000..4910cd3
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/magic.h>
+
+/* 62aa81d7c4c24b90fdb61da70ac0dbbc414f9939 (4.13) */
+#ifndef OCFS2_SUPER_MAGIC
+#define OCFS2_SUPER_MAGIC 0x7461636f
+#endif
+
+/* 67e9c74b8a873408c27ac9a8e4c1d1c8d72c93ff (4.5) */
+#ifndef CGROUP2_SUPER_MAGIC
+#define CGROUP2_SUPER_MAGIC 0x63677270
+#endif
+
+/* 4282d60689d4f21b40692029080440cc58e8a17d (4.1) */
+#ifndef TRACEFS_MAGIC
+#define TRACEFS_MAGIC 0x74726163
+#endif
+
+/* e149ed2b805fefdccf7ccdfc19eca22fdd4514ac (3.19) */
+#ifndef NSFS_MAGIC
+#define NSFS_MAGIC 0x6e736673
+#endif
+
+/* b2197755b2633e164a439682fb05a9b5ea48f706 (4.4) */
+#ifndef BPF_FS_MAGIC
+#define BPF_FS_MAGIC 0xcafe4a11
+#endif
+
+/* Not exposed yet (4.20). Defined at ipc/mqueue.c */
+#ifndef MQUEUE_MAGIC
+#define MQUEUE_MAGIC 0x19800202
+#endif
diff --git a/src/basic/missing_mman.h b/src/basic/missing_mman.h
new file mode 100644 (file)
index 0000000..7ff12f7
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/mman.h>
+
+#ifndef MFD_ALLOW_SEALING
+#define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
+#endif
diff --git a/src/basic/missing_network.h b/src/basic/missing_network.h
new file mode 100644 (file)
index 0000000..59a8cd2
--- /dev/null
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/loop.h>
+#include <linux/rtnetlink.h>
+#include <net/ethernet.h>
+
+#include "missing_ethtool.h"
+#include "missing_fib_rules.h"
+#include "missing_fou.h"
+#include "missing_if_bridge.h"
+#include "missing_if_link.h"
+#include "missing_if_tunnel.h"
+#include "missing_vxcan.h"
+
+/* if.h */
+/* The following two defines are actually available in the kernel headers for longer, but we define them here anyway,
+ * since that makes it easier to use them in conjunction with the glibc net/if.h header which conflicts with
+ * linux/if.h. */
+#ifndef IF_OPER_UNKNOWN
+#define IF_OPER_UNKNOWN 0
+#endif
+
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000
+#endif
+
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000
+#endif
+
+/* if_addr.h */
+#if !HAVE_IFA_FLAGS
+#define IFA_FLAGS 8
+#endif
+
+#ifndef IFA_F_MANAGETEMPADDR
+#define IFA_F_MANAGETEMPADDR 0x100
+#endif
+
+#ifndef IFA_F_NOPREFIXROUTE
+#define IFA_F_NOPREFIXROUTE 0x200
+#endif
+
+#ifndef IFA_F_MCAUTOJOIN
+#define IFA_F_MCAUTOJOIN 0x400
+#endif
+
+/* if_arp.h */
+#ifndef ARPHRD_IP6GRE
+#define ARPHRD_IP6GRE 823
+#endif
+
+/* if_bonding.h */
+#ifndef BOND_XMIT_POLICY_ENCAP23
+#define BOND_XMIT_POLICY_ENCAP23 3
+#endif
+
+#ifndef BOND_XMIT_POLICY_ENCAP34
+#define BOND_XMIT_POLICY_ENCAP34 4
+#endif
+
+/* if_tun.h */
+#ifndef IFF_MULTI_QUEUE
+#define IFF_MULTI_QUEUE 0x100
+#endif
+
+/* in6.h */
+#ifndef IPV6_UNICAST_IF
+#define IPV6_UNICAST_IF 76
+#endif
+
+/* ip.h */
+#ifndef IPV4_MIN_MTU
+#define IPV4_MIN_MTU 68
+#endif
+
+/* ipv6.h */
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
+
+/* loop.h */
+#if !HAVE_LO_FLAGS_PARTSCAN
+#define LO_FLAGS_PARTSCAN 8
+#endif
+
+#ifndef LOOP_CTL_REMOVE
+#define LOOP_CTL_REMOVE 0x4C81
+#endif
+
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
+/* netdevice.h */
+#ifndef NET_ADDR_RANDOM
+#define NET_ADDR_RANDOM 1
+#endif
+
+#ifndef NET_NAME_UNKNOWN
+#define NET_NAME_UNKNOWN 0
+#endif
+
+#ifndef NET_NAME_ENUM
+#define NET_NAME_ENUM 1
+#endif
+
+#ifndef NET_NAME_PREDICTABLE
+#define NET_NAME_PREDICTABLE 2
+#endif
+
+#ifndef NET_NAME_USER
+#define NET_NAME_USER 3
+#endif
+
+#ifndef NET_NAME_RENAMED
+#define NET_NAME_RENAMED 4
+#endif
+
+/* netlink.h */
+#ifndef NETLINK_LIST_MEMBERSHIPS /* b42be38b2778eda2237fc759e55e3b698b05b315 (4.2) */
+#define NETLINK_LIST_MEMBERSHIPS 9
+#endif
+
+/* rtnetlink.h */
+#ifndef RTA_PREF
+#define RTA_PREF 20
+#endif
+
+#ifndef RTAX_QUICKACK
+#define RTAX_QUICKACK 15
+#endif
+
+#ifndef RTA_EXPIRES
+#define RTA_EXPIRES 23
+#endif
+
+/* Note that LOOPBACK_IFINDEX is currently not exported by the
+ * kernel/glibc, but hardcoded internally by the kernel.  However, as
+ * it is exported to userspace indirectly via rtnetlink and the
+ * ioctls, and made use of widely we define it here too, in a way that
+ * is compatible with the kernel's internal definition. */
+#ifndef LOOPBACK_IFINDEX
+#define LOOPBACK_IFINDEX 1
+#endif
+
+/* Not exposed yet. Similar values are defined in net/ethernet.h */
+#ifndef ETHERTYPE_LLDP
+#define ETHERTYPE_LLDP 0x88cc
+#endif
diff --git a/src/basic/missing_prctl.h b/src/basic/missing_prctl.h
new file mode 100644 (file)
index 0000000..f80cd17
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/prctl.h>
+
+/* 58319057b7847667f0c9585b9de0e8932b0fdb08 (4.3) */
+#ifndef PR_CAP_AMBIENT
+#define PR_CAP_AMBIENT 47
+
+#define PR_CAP_AMBIENT_IS_SET    1
+#define PR_CAP_AMBIENT_RAISE     2
+#define PR_CAP_AMBIENT_LOWER     3
+#define PR_CAP_AMBIENT_CLEAR_ALL 4
+#endif
diff --git a/src/basic/missing_random.h b/src/basic/missing_random.h
new file mode 100644 (file)
index 0000000..2e76031
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if USE_SYS_RANDOM_H
+#  include <sys/random.h>
+#else
+#  include <linux/random.h>
+#endif
+
+#ifndef GRND_NONBLOCK
+#define GRND_NONBLOCK 0x0001
+#endif
+
+#ifndef GRND_RANDOM
+#define GRND_RANDOM 0x0002
+#endif
diff --git a/src/basic/missing_resource.h b/src/basic/missing_resource.h
new file mode 100644 (file)
index 0000000..22ba8ab
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/resource.h>
+
+#ifndef RLIMIT_RTTIME
+#define RLIMIT_RTTIME 15
+#endif
+
+/* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */
+#define _RLIMIT_MAX (RLIMIT_RTTIME+1 > RLIMIT_NLIMITS ? RLIMIT_RTTIME+1 : RLIMIT_NLIMITS)
diff --git a/src/basic/missing_sched.h b/src/basic/missing_sched.h
new file mode 100644 (file)
index 0000000..baa3913
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sched.h>
+
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+
+/* Not exposed yet. Defined at include/linux/sched.h */
+#ifndef PF_KTHREAD
+#define PF_KTHREAD 0x00200000
+#endif
+
+/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of the same
+ * name, which we need in userspace at various places but is not defined in userspace currently, neither under this
+ * name nor any other. */
+/* Not exposed yet. Defined at include/linux/sched.h */
+#ifndef TASK_COMM_LEN
+#define TASK_COMM_LEN 16
+#endif
diff --git a/src/basic/missing_securebits.h b/src/basic/missing_securebits.h
new file mode 100644 (file)
index 0000000..40d6ec9
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <linux/securebits.h>
+
+/* 746bf6d64275be0c65b0631d8a72b16f1454cfa1 (4.3) */
+#ifndef SECURE_NO_CAP_AMBIENT_RAISE
+#define SECURE_NO_CAP_AMBIENT_RAISE        6
+#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7  /* make bit-6 immutable */
+#define SECBIT_NO_CAP_AMBIENT_RAISE        (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
+#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED))
+
+#undef  SECURE_ALL_BITS
+#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) |                 \
+                         issecure_mask(SECURE_NO_SETUID_FIXUP) |        \
+                         issecure_mask(SECURE_KEEP_CAPS) |              \
+                         issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
+#endif
diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h
new file mode 100644 (file)
index 0000000..a5fd457
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/socket.h>
+
+#if HAVE_LINUX_VM_SOCKETS_H
+#include <linux/vm_sockets.h>
+#else
+#define VMADDR_CID_ANY -1U
+struct sockaddr_vm {
+        unsigned short svm_family;
+        unsigned short svm_reserved1;
+        unsigned int svm_port;
+        unsigned int svm_cid;
+        unsigned char svm_zero[sizeof(struct sockaddr) -
+                               sizeof(unsigned short) -
+                               sizeof(unsigned short) -
+                               sizeof(unsigned int) -
+                               sizeof(unsigned int)];
+};
+#endif /* !HAVE_LINUX_VM_SOCKETS_H */
+
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+
+#ifndef SO_PEERGROUPS
+#define SO_PEERGROUPS 59
+#endif
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+/* Not exposed yet. Defined in include/linux/socket.h. */
+#ifndef SOL_SCTP
+#define SOL_SCTP 132
+#endif
+
+/* Not exposed yet. Defined in include/linux/socket.h */
+#ifndef SCM_SECURITY
+#define SCM_SECURITY 0x03
+#endif
+
+/* netinet/in.h */
+#ifndef IP_FREEBIND
+#define IP_FREEBIND 15
+#endif
+
+#ifndef IP_TRANSPARENT
+#define IP_TRANSPARENT 19
+#endif
diff --git a/src/basic/missing_stat.h b/src/basic/missing_stat.h
new file mode 100644 (file)
index 0000000..5116206
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/types.h>
+#include <sys/stat.h>
+
+#if WANT_LINUX_STAT_H
+#include <linux/stat.h>
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#if !HAVE_STRUCT_STATX
+struct statx_timestamp {
+        __s64 tv_sec;
+        __u32 tv_nsec;
+        __s32 __reserved;
+};
+struct statx {
+        __u32 stx_mask;
+        __u32 stx_blksize;
+        __u64 stx_attributes;
+        __u32 stx_nlink;
+        __u32 stx_uid;
+        __u32 stx_gid;
+        __u16 stx_mode;
+        __u16 __spare0[1];
+        __u64 stx_ino;
+        __u64 stx_size;
+        __u64 stx_blocks;
+        __u64 stx_attributes_mask;
+        struct statx_timestamp stx_atime;
+        struct statx_timestamp stx_btime;
+        struct statx_timestamp stx_ctime;
+        struct statx_timestamp stx_mtime;
+        __u32 stx_rdev_major;
+        __u32 stx_rdev_minor;
+        __u32 stx_dev_major;
+        __u32 stx_dev_minor;
+        __u64 __spare2[14];
+};
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#ifndef STATX_BTIME
+#define STATX_BTIME 0x00000800U
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#ifndef AT_STATX_DONT_SYNC
+#define AT_STATX_DONT_SYNC 0x4000
+#endif
diff --git a/src/basic/missing_stdlib.h b/src/basic/missing_stdlib.h
new file mode 100644 (file)
index 0000000..188a8d4
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdlib.h>
+
+/* stdlib.h */
+#if !HAVE_SECURE_GETENV
+#  if HAVE___SECURE_GETENV
+#    define secure_getenv __secure_getenv
+#  else
+#    error "neither secure_getenv nor __secure_getenv are available"
+#  endif
+#endif
index 93c60458bfe7afc947954caa0ac3a99a7e15aca7..d5d4b26acb3776a188329e6a863a13a7ad759975 100644 (file)
@@ -3,7 +3,22 @@
 
 /* Missing glibc definitions to access certain kernel APIs */
 
+#include <fcntl.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
+#include <unistd.h>
+
+#ifdef ARCH_MIPS
+#include <asm/sgidefs.h>
+#endif
+
+#include "missing_keyctl.h"
+#include "missing_stat.h"
+
+/* linux/kcmp.h */
+#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */
+#define KCMP_FILE 0
+#endif
 
 #if !HAVE_PIVOT_ROOT
 static inline int missing_pivot_root(const char *new_root, const char *put_old) {
@@ -252,7 +267,7 @@ static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long i
 /* ======================================================================= */
 
 #if !HAVE_KEYCTL
-static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
+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);
 #  else
diff --git a/src/basic/missing_timerfd.h b/src/basic/missing_timerfd.h
new file mode 100644 (file)
index 0000000..6b04044
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/timerfd.h>
+
+#ifndef TFD_TIMER_CANCEL_ON_SET
+#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#endif
diff --git a/src/basic/missing_type.h b/src/basic/missing_type.h
new file mode 100644 (file)
index 0000000..bf8a6ca
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <uchar.h>
+
+#if !HAVE_CHAR32_T
+#define char32_t uint32_t
+#endif
+
+#if !HAVE_CHAR16_T
+#define char16_t uint16_t
+#endif
diff --git a/src/basic/missing_vxcan.h b/src/basic/missing_vxcan.h
new file mode 100644 (file)
index 0000000..be430f7
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !HAVE_LINUX_CAN_VXCAN_H /* linux@a8f820a380a2a06fc4fe1a54159067958f800929 (4.12) */
+enum {
+        VXCAN_INFO_UNSPEC,
+        VXCAN_INFO_PEER,
+
+        __VXCAN_INFO_MAX
+#define VXCAN_INFO_MAX        (__VXCAN_INFO_MAX - 1)
+};
+#endif
diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c
new file mode 100644 (file)
index 0000000..1e946a0
--- /dev/null
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio_ext.h>
+#include <sys/mount.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "missing.h"
+#include "mountpoint-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+
+/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
+ * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
+ * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
+ * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
+ * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
+ * with large file handles anyway. */
+#define ORIGINAL_MAX_HANDLE_SZ 128
+
+int name_to_handle_at_loop(
+                int fd,
+                const char *path,
+                struct file_handle **ret_handle,
+                int *ret_mnt_id,
+                int flags) {
+
+        _cleanup_free_ struct file_handle *h = NULL;
+        size_t n = ORIGINAL_MAX_HANDLE_SZ;
+
+        /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
+         * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
+         * start value, it is not an upper bound on the buffer size required.
+         *
+         * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed
+         * as NULL if there's no interest in either. */
+
+        for (;;) {
+                int mnt_id = -1;
+
+                h = malloc0(offsetof(struct file_handle, f_handle) + n);
+                if (!h)
+                        return -ENOMEM;
+
+                h->handle_bytes = n;
+
+                if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) {
+
+                        if (ret_handle)
+                                *ret_handle = TAKE_PTR(h);
+
+                        if (ret_mnt_id)
+                                *ret_mnt_id = mnt_id;
+
+                        return 0;
+                }
+                if (errno != EOVERFLOW)
+                        return -errno;
+
+                if (!ret_handle && ret_mnt_id && mnt_id >= 0) {
+
+                        /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the
+                         * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to
+                         * be filled in, and the caller was interested in only the mount ID an nothing else. */
+
+                        *ret_mnt_id = mnt_id;
+                        return 0;
+                }
+
+                /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something
+                 * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small
+                 * buffer. In that case propagate EOVERFLOW */
+                if (h->handle_bytes <= n)
+                        return -EOVERFLOW;
+
+                /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */
+                n = h->handle_bytes;
+                if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */
+                        return -EOVERFLOW;
+
+                h = mfree(h);
+        }
+}
+
+static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
+        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+        _cleanup_free_ char *fdinfo = NULL;
+        _cleanup_close_ int subfd = -1;
+        char *p;
+        int r;
+
+        if ((flags & AT_EMPTY_PATH) && isempty(filename))
+                xsprintf(path, "/proc/self/fdinfo/%i", fd);
+        else {
+                subfd = openat(fd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_FOLLOW ? 0 : O_NOFOLLOW));
+                if (subfd < 0)
+                        return -errno;
+
+                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
+        }
+
+        r = read_full_file(path, &fdinfo, NULL);
+        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
+                return -EOPNOTSUPP;
+        if (r < 0)
+                return r;
+
+        p = startswith(fdinfo, "mnt_id:");
+        if (!p) {
+                p = strstr(fdinfo, "\nmnt_id:");
+                if (!p) /* The mnt_id field is a relatively new addition */
+                        return -EOPNOTSUPP;
+
+                p += 8;
+        }
+
+        p += strspn(p, WHITESPACE);
+        p[strcspn(p, WHITESPACE)] = 0;
+
+        return safe_atoi(p, mnt_id);
+}
+
+int fd_is_mount_point(int fd, const char *filename, int flags) {
+        _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
+        int mount_id = -1, mount_id_parent = -1;
+        bool nosupp = false, check_st_dev = true;
+        struct stat a, b;
+        int r;
+
+        assert(fd >= 0);
+        assert(filename);
+
+        /* First we will try the name_to_handle_at() syscall, which
+         * tells us the mount id and an opaque file "handle". It is
+         * not supported everywhere though (kernel compile-time
+         * option, not all file systems are hooked up). If it works
+         * the mount id is usually good enough to tell us whether
+         * something is a mount point.
+         *
+         * If that didn't work we will try to read the mount id from
+         * /proc/self/fdinfo/<fd>. This is almost as good as
+         * name_to_handle_at(), however, does not return the
+         * opaque file handle. The opaque file handle is pretty useful
+         * to detect the root directory, which we should always
+         * consider a mount point. Hence we use this only as
+         * fallback. Exporting the mnt_id in fdinfo is a pretty recent
+         * kernel addition.
+         *
+         * As last fallback we do traditional fstat() based st_dev
+         * comparisons. This is how things were traditionally done,
+         * but unionfs breaks this since it exposes file
+         * systems with a variety of st_dev reported. Also, btrfs
+         * subvolumes have different st_dev, even though they aren't
+         * real mounts of their own. */
+
+        r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
+        if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
+                /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked
+                 * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount
+                 * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness
+                 * (EINVAL): fall back to simpler logic. */
+                goto fallback_fdinfo;
+        else if (r == -EOPNOTSUPP)
+                /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs
+                 * supports it (in which case it is a mount point), otherwise fallback to the traditional stat()
+                 * logic */
+                nosupp = true;
+        else if (r < 0)
+                return r;
+
+        r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
+        if (r == -EOPNOTSUPP) {
+                if (nosupp)
+                        /* Neither parent nor child do name_to_handle_at()?  We have no choice but to fall back. */
+                        goto fallback_fdinfo;
+                else
+                        /* The parent can't do name_to_handle_at() but the directory we are interested in can?  If so,
+                         * it must be a mount point. */
+                        return 1;
+        } else if (r < 0)
+                return r;
+
+        /* The parent can do name_to_handle_at() but the
+         * directory we are interested in can't? If so, it
+         * must be a mount point. */
+        if (nosupp)
+                return 1;
+
+        /* If the file handle for the directory we are
+         * interested in and its parent are identical, we
+         * assume this is the root directory, which is a mount
+         * point. */
+
+        if (h->handle_bytes == h_parent->handle_bytes &&
+            h->handle_type == h_parent->handle_type &&
+            memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0)
+                return 1;
+
+        return mount_id != mount_id_parent;
+
+fallback_fdinfo:
+        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
+        if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM))
+                goto fallback_fstat;
+        if (r < 0)
+                return r;
+
+        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
+        if (r < 0)
+                return r;
+
+        if (mount_id != mount_id_parent)
+                return 1;
+
+        /* Hmm, so, the mount ids are the same. This leaves one
+         * special case though for the root file system. For that,
+         * let's see if the parent directory has the same inode as we
+         * are interested in. Hence, let's also do fstat() checks now,
+         * too, but avoid the st_dev comparisons, since they aren't
+         * that useful on unionfs mounts. */
+        check_st_dev = false;
+
+fallback_fstat:
+        /* yay for fstatat() taking a different set of flags than the other
+         * _at() above */
+        if (flags & AT_SYMLINK_FOLLOW)
+                flags &= ~AT_SYMLINK_FOLLOW;
+        else
+                flags |= AT_SYMLINK_NOFOLLOW;
+        if (fstatat(fd, filename, &a, flags) < 0)
+                return -errno;
+
+        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
+                return -errno;
+
+        /* A directory with same device and inode as its parent? Must
+         * be the root directory */
+        if (a.st_dev == b.st_dev &&
+            a.st_ino == b.st_ino)
+                return 1;
+
+        return check_st_dev && (a.st_dev != b.st_dev);
+}
+
+/* flags can be AT_SYMLINK_FOLLOW or 0 */
+int path_is_mount_point(const char *t, const char *root, int flags) {
+        _cleanup_free_ char *canonical = NULL;
+        _cleanup_close_ int fd = -1;
+        int r;
+
+        assert(t);
+        assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
+
+        if (path_equal(t, "/"))
+                return 1;
+
+        /* we need to resolve symlinks manually, we can't just rely on
+         * fd_is_mount_point() to do that for us; if we have a structure like
+         * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
+         * look at needs to be /usr, not /. */
+        if (flags & AT_SYMLINK_FOLLOW) {
+                r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical);
+                if (r < 0)
+                        return r;
+
+                t = canonical;
+        }
+
+        fd = open_parent(t, O_PATH|O_CLOEXEC, 0);
+        if (fd < 0)
+                return -errno;
+
+        return fd_is_mount_point(fd, last_path_component(t), flags);
+}
+
+int path_get_mnt_id(const char *path, int *ret) {
+        int r;
+
+        r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
+        if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
+                return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
+
+        return r;
+}
+
+bool fstype_is_network(const char *fstype) {
+        const char *x;
+
+        x = startswith(fstype, "fuse.");
+        if (x)
+                fstype = x;
+
+        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");
+}
+
+bool fstype_can_uid_gid(const char *fstype) {
+
+        /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
+         * current and future. */
+
+        return STR_IN_SET(fstype,
+                          "adfs",
+                          "fat",
+                          "hfs",
+                          "hpfs",
+                          "iso9660",
+                          "msdos",
+                          "ntfs",
+                          "vfat");
+}
+
+int dev_is_devtmpfs(void) {
+        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+        int mount_id, r;
+        char *e;
+
+        r = path_get_mnt_id("/dev", &mount_id);
+        if (r < 0)
+                return r;
+
+        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+        if (!proc_self_mountinfo)
+                return -errno;
+
+        (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                int mid;
+
+                r = read_line(proc_self_mountinfo, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                if (sscanf(line, "%i", &mid) != 1)
+                        continue;
+
+                if (mid != mount_id)
+                        continue;
+
+                e = strstr(line, " - ");
+                if (!e)
+                        continue;
+
+                /* accept any name that starts with the currently expected type */
+                if (startswith(e + 3, "devtmpfs"))
+                        return true;
+        }
+
+        return false;
+}
+
+const char *mount_propagation_flags_to_string(unsigned long flags) {
+
+        switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) {
+        case 0:
+                return "";
+        case MS_SHARED:
+                return "shared";
+        case MS_SLAVE:
+                return "slave";
+        case MS_PRIVATE:
+                return "private";
+        }
+
+        return NULL;
+}
+
+int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
+
+        if (isempty(name))
+                *ret = 0;
+        else if (streq(name, "shared"))
+                *ret = MS_SHARED;
+        else if (streq(name, "slave"))
+                *ret = MS_SLAVE;
+        else if (streq(name, "private"))
+                *ret = MS_PRIVATE;
+        else
+                return -EINVAL;
+        return 0;
+}
diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h
new file mode 100644 (file)
index 0000000..5398836
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags);
+
+int path_get_mnt_id(const char *path, int *ret);
+
+int fd_is_mount_point(int fd, const char *filename, int flags);
+int path_is_mount_point(const char *path, const char *root, int flags);
+
+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);
+bool fstype_can_uid_gid(const char *fstype);
+
+int dev_is_devtmpfs(void);
+
+const char *mount_propagation_flags_to_string(unsigned long flags);
+int mount_propagation_flags_from_string(const char *name, unsigned long *ret);
index e7c054d8e4c1192af211baa14938a234f3ec9c6b..7cbb71819b70598263916ca7ef2203f1f24dc7fe 100644 (file)
@@ -21,13 +21,11 @@ static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash
 }
 
 static inline OrderedSet* ordered_set_free(OrderedSet *s) {
-        ordered_hashmap_free((OrderedHashmap*) s);
-        return NULL;
+        return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s);
 }
 
 static inline OrderedSet* ordered_set_free_free(OrderedSet *s) {
-        ordered_hashmap_free_free((OrderedHashmap*) s);
-        return NULL;
+        return (OrderedSet*) ordered_hashmap_free_free((OrderedHashmap*) s);
 }
 
 static inline int ordered_set_put(OrderedSet *s, void *p) {
index ce8bb12670bea1cb2f584670bb97b49b4515d78a..87724af693068b624a0f9f0a366404ca3597239c 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <linux/oom.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include "missing.h"
 #include "parse-util.h"
 #include "process-util.h"
+#include "stat-util.h"
 #include "string-util.h"
 
 int parse_boolean(const char *v) {
-        assert(v);
+        if (!v)
+                return -EINVAL;
 
         if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
                 return 1;
@@ -731,17 +734,30 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
 }
 
 int parse_dev(const char *s, dev_t *ret) {
+        const char *major;
         unsigned x, y;
-        dev_t d;
+        size_t n;
+        int r;
 
-        if (sscanf(s, "%u:%u", &x, &y) != 2)
+        n = strspn(s, DIGITS);
+        if (n == 0)
                 return -EINVAL;
-
-        d = makedev(x, y);
-        if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
+        if (s[n] != ':')
                 return -EINVAL;
 
-        *ret = d;
+        major = strndupa(s, n);
+        r = safe_atou(major, &x);
+        if (r < 0)
+                return r;
+
+        r = safe_atou(s + n + 1, &y);
+        if (r < 0)
+                return r;
+
+        if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
+                return -ERANGE;
+
+        *ret = makedev(x, y);
         return 0;
 }
 
index eb64c886e6c340e5da0974e1d9defc5e8f2ad197..995f39f16ef0ee770db269a6e943334010f970a3 100644 (file)
@@ -110,7 +110,7 @@ int path_make_absolute_cwd(const char *p, char **ret) {
                 if (r < 0)
                         return r;
 
-                c = path_join(NULL, cwd, p);
+                c = path_join(cwd, p);
         }
         if (!c)
                 return -ENOMEM;
@@ -481,18 +481,62 @@ bool path_equal_or_files_same(const char *a, const char *b, int flags) {
         return path_equal(a, b) || files_same(a, b, flags) > 0;
 }
 
-char* path_join(const char *root, const char *path, const char *rest) {
-        assert(path);
+char* path_join_internal(const char *first, ...) {
+        char *joined, *q;
+        const char *p;
+        va_list ap;
+        bool slash;
+        size_t sz;
+
+        /* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
+         * already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
+         * removed. The string returned is hence always equal to or longer than the sum of the lengths of each
+         * individual string.
+         *
+         * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
+         * are optional.
+         *
+         * Examples:
+         *
+         * path_join("foo", "bar") → "foo/bar"
+         * path_join("foo/", "bar") → "foo/bar"
+         * path_join("", "foo", "", "bar", "") → "foo/bar" */
+
+        sz = strlen_ptr(first);
+        va_start(ap, first);
+        while ((p = va_arg(ap, char*)) != (const char*) -1)
+                if (!isempty(p))
+                        sz += 1 + strlen(p);
+        va_end(ap);
+
+        joined = new(char, sz + 1);
+        if (!joined)
+                return NULL;
 
-        if (!isempty(root))
-                return strjoin(root, endswith(root, "/") ? "" : "/",
-                               path[0] == '/' ? path+1 : path,
-                               rest ? (endswith(path, "/") ? "" : "/") : NULL,
-                               rest && rest[0] == '/' ? rest+1 : rest);
-        else
-                return strjoin(path,
-                               rest ? (endswith(path, "/") ? "" : "/") : NULL,
-                               rest && rest[0] == '/' ? rest+1 : rest);
+        if (!isempty(first)) {
+                q = stpcpy(joined, first);
+                slash = endswith(first, "/");
+        } else {
+                /* Skip empty items */
+                joined[0] = 0;
+                q = joined;
+                slash = true; /* no need to generate a slash anymore */
+        }
+
+        va_start(ap, first);
+        while ((p = va_arg(ap, char*)) != (const char*) -1) {
+                if (isempty(p))
+                        continue;
+
+                if (!slash && p[0] != '/')
+                        *(q++) = '/';
+
+                q = stpcpy(q, p);
+                slash = endswith(p, "/");
+        }
+        va_end(ap);
+
+        return joined;
 }
 
 int find_binary(const char *name, char **ret) {
@@ -750,6 +794,9 @@ const char *last_path_component(const char *path) {
 
         unsigned l, k;
 
+        if (!path)
+                return NULL;
+
         l = k = strlen(path);
         if (l == 0) /* special case — an empty string */
                 return path;
@@ -766,6 +813,37 @@ const char *last_path_component(const char *path) {
         return path + k;
 }
 
+int path_extract_filename(const char *p, char **ret) {
+        _cleanup_free_ char *a = NULL;
+        const char *c, *e = NULL, *q;
+
+        /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
+         * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */
+
+        if (!p)
+                return -EINVAL;
+
+        c = last_path_component(p);
+
+        for (q = c; *q != 0; q++)
+                if (*q != '/')
+                        e = q + 1;
+
+        if (!e) /* no valid character? */
+                return -EINVAL;
+
+        a = strndup(c, e - c);
+        if (!a)
+                return -ENOMEM;
+
+        if (!filename_is_valid(a))
+                return -EINVAL;
+
+        *ret = TAKE_PTR(a);
+
+        return 0;
+}
+
 bool filename_is_valid(const char *p) {
         const char *e;
 
index e2a51ff33a29757f3c98a3078b8c8c3e5cf280b9..78db41b855c2ff13b55e4305bd2b79378d5e28ed 100644 (file)
@@ -49,7 +49,9 @@ char* path_startswith(const char *path, const char *prefix) _pure_;
 int path_compare(const char *a, const char *b) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
 bool path_equal_or_files_same(const char *a, const char *b, int flags);
-char* path_join(const char *root, const char *path, const char *rest);
+char* path_join_internal(const char *first, ...);
+#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
+
 char* path_simplify(char *path, bool kill_dots);
 
 static inline bool path_equal_ptr(const char *a, const char *b) {
@@ -133,6 +135,7 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
 
 char* dirname_malloc(const char *path);
 const char *last_path_component(const char *path);
+int path_extract_filename(const char *p, char **ret);
 
 bool filename_is_valid(const char *p) _pure_;
 bool path_is_valid(const char *p) _pure_;
index d1a34338f6d07556671faf75799bfe81f800f3de..5b700df33a973f42365a476494b6a5aa24d0a4ab 100644 (file)
@@ -35,6 +35,7 @@
 #include "missing.h"
 #include "process-util.h"
 #include "raw-clone.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "stat-util.h"
 #include "string-table.h"
@@ -1172,7 +1173,7 @@ void reset_cached_pid(void) {
  * 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__));
+extern void* __dso_handle _weak_;
 
 pid_t getpid_cached(void) {
         static bool installed = false;
@@ -1401,6 +1402,14 @@ int safe_fork_full(
                 }
         }
 
+        if (flags & FORK_RLIMIT_NOFILE_SAFE) {
+                r = rlimit_nofile_safe();
+                if (r < 0) {
+                        log_full_errno(prio, r, "Failed to lower RLIMIT_NOFILE's soft limit to 1K: %m");
+                        _exit(EXIT_FAILURE);
+                }
+        }
+
         if (ret_pid)
                 *ret_pid = getpid_cached();
 
@@ -1512,6 +1521,8 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret
                 safe_close_above_stdio(fd);
         }
 
+        (void) rlimit_nofile_safe();
+
         /* Count arguments */
         va_start(ap, path);
         for (n = 0; va_arg(ap, char*); n++)
index af47513fab0f0b16ae210a5d1084de8ea3719337..496e14d3de17667217e455c43471bf9f9dd39b8c 100644 (file)
@@ -142,15 +142,16 @@ void reset_cached_pid(void);
 int must_be_root(void);
 
 typedef enum ForkFlags {
-        FORK_RESET_SIGNALS = 1 << 0,
-        FORK_CLOSE_ALL_FDS = 1 << 1,
-        FORK_DEATHSIG      = 1 << 2,
-        FORK_NULL_STDIO    = 1 << 3,
-        FORK_REOPEN_LOG    = 1 << 4,
-        FORK_LOG           = 1 << 5,
-        FORK_WAIT          = 1 << 6,
-        FORK_NEW_MOUNTNS   = 1 << 7,
-        FORK_MOUNTNS_SLAVE = 1 << 8,
+        FORK_RESET_SIGNALS      = 1 << 0, /* Reset all signal handlers and signal mask */
+        FORK_CLOSE_ALL_FDS      = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
+        FORK_DEATHSIG           = 1 << 2, /* Set PR_DEATHSIG in the child */
+        FORK_NULL_STDIO         = 1 << 3, /* Connect 0,1,2 to /dev/null */
+        FORK_REOPEN_LOG         = 1 << 4, /* Reopen log connection */
+        FORK_LOG                = 1 << 5, /* Log above LOG_DEBUG log level about failures */
+        FORK_WAIT               = 1 << 6, /* Wait until child exited */
+        FORK_NEW_MOUNTNS        = 1 << 7, /* Run child in its own mount namespace */
+        FORK_MOUNTNS_SLAVE      = 1 << 8, /* Make child's mount namespace MS_SLAVE */
+        FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
 } ForkFlags;
 
 int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
index 4a36ad51195aa9e1b54f489c63fd939e15b12561..f7decf60b6189a7206577dc44ce650b2b148273e 100644 (file)
@@ -7,7 +7,6 @@
 #include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <linux/random.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
similarity index 94%
rename from src/shared/rlimit-util.c
rename to src/basic/rlimit-util.c
index c133f84b7e90e24c7dd10149d09188b11beeb371..74b3a023f18ab6c6fa218397a56f8447149bcd91 100644 (file)
@@ -389,3 +389,22 @@ int rlimit_nofile_bump(int limit) {
 
         return 0;
 }
+
+int rlimit_nofile_safe(void) {
+        struct rlimit rl;
+
+        /* Resets RLIMIT_NOFILE's soft limit FD_SETSIZE (i.e. 1024), for compatibility with software still using
+         * select() */
+
+        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+                return log_debug_errno(errno, "Failed to query RLIMIT_NOFILE: %m");
+
+        if (rl.rlim_cur <= FD_SETSIZE)
+                return 0;
+
+        rl.rlim_cur = FD_SETSIZE;
+        if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
+                return log_debug_errno(errno, "Failed to lower RLIMIT_NOFILE's soft limit to " RLIM_FMT ": %m", rl.rlim_cur);
+
+        return 1;
+}
similarity index 96%
rename from src/shared/rlimit-util.h
rename to src/basic/rlimit-util.h
index 6139af3ff50ff5fec8e5cf56bdbfc2719cd676e4..d4fca2b8556d9b00b3a080c02c11e64737dd8ccb 100644 (file)
@@ -22,3 +22,4 @@ void rlimit_free_all(struct rlimit **rl);
 #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
 
 int rlimit_nofile_bump(int limit);
+int rlimit_nofile_safe(void);
index 1503f1032a8282b5b006b1cb95808b28b784139b..0c957c9b3a8c22588ddab818f90ecf8f92f5f344 100644 (file)
@@ -15,7 +15,7 @@
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stat-util.h"
index 0a2d7f0358ea78cfba3d2bc1f953664bdb0097e6..3ee2b97e3768ba967bd5fd1388ffbc33558bf2c8 100644 (file)
@@ -22,3 +22,11 @@ static inline void rm_rf_physical_and_free(char *p) {
         free(p);
 }
 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free);
+
+/* Similar as above, but also has magic btrfs subvolume powers */
+static inline void rm_rf_subvolume_and_free(char *p) {
+        PROTECT_ERRNO;
+        (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+        free(p);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_subvolume_and_free);
diff --git a/src/basic/securebits.h b/src/basic/securebits.h
deleted file mode 100644 (file)
index e3b7538..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#pragma once
-
-/* This is minimal version of Linux' linux/securebits.h header file,
- * which is licensed GPL2 */
-
-#define SECUREBITS_DEFAULT 0x00000000
-
-/* When set UID 0 has no special privileges. When unset, we support
-   inheritance of root-permissions and suid-root executable under
-   compatibility mode. We raise the effective and inheritable bitmasks
-   *of the executable file* if the effective uid of the new process is
-   0. If the real uid is 0, we raise the effective (legacy) bit of the
-   executable file. */
-#define SECURE_NOROOT                  0
-#define SECURE_NOROOT_LOCKED           1  /* make bit-0 immutable */
-
-/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
-   When unset, to provide compatibility with old programs relying on
-   set*uid to gain/lose privilege, transitions to/from uid 0 cause
-   capabilities to be gained/lost. */
-#define SECURE_NO_SETUID_FIXUP         2
-#define SECURE_NO_SETUID_FIXUP_LOCKED  3  /* make bit-2 immutable */
-
-/* When set, a process can retain its capabilities even after
-   transitioning to a non-root user (the set-uid fixup suppressed by
-   bit 2). Bit-4 is cleared when a process calls exec(); setting both
-   bit 4 and 5 will create a barrier through exec that no exec()'d
-   child can use this feature again. */
-#define SECURE_KEEP_CAPS               4
-#define SECURE_KEEP_CAPS_LOCKED                5  /* make bit-4 immutable */
-
-/* Each securesetting is implemented using two bits. One bit specifies
-   whether the setting is on or off. The other bit specify whether the
-   setting is locked or not. A setting which is locked cannot be
-   changed from user-level. */
-#define issecure_mask(X)       (1 << (X))
-#define issecure(X)            (issecure_mask(X) & current_cred_xxx(securebits))
-
-#define SECURE_ALL_BITS                (issecure_mask(SECURE_NOROOT) | \
-                                 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
-                                 issecure_mask(SECURE_KEEP_CAPS))
-#define SECURE_ALL_LOCKS       (SECURE_ALL_BITS << 1)
index d5228f67463fbbd7c8fd6bc4efd922d5938c2536..dc06f3d0740c59a24e953964fa00bf170efe0cfb 100644 (file)
@@ -366,11 +366,9 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode)
                 if (r < 0)
                         return r;
 
-                abspath = path_join(NULL, p, path);
-                if (!abspath)
+                path = abspath = path_join(p, path);
+                if (!path)
                         return -ENOMEM;
-
-                path = abspath;
         }
 
         r = selinux_create_file_prepare_abspath(path, mode);
index 0d99d5550d9f93b075219b60e5336a541db28164..2a80632b79fb218f7f95cb769c00d82b21a1bdc0 100644 (file)
@@ -9,13 +9,11 @@ Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
 #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
 
 static inline Set *set_free(Set *s) {
-        internal_hashmap_free(HASHMAP_BASE(s));
-        return NULL;
+        return (Set*) internal_hashmap_free(HASHMAP_BASE(s), NULL, NULL);
 }
 
 static inline Set *set_free_free(Set *s) {
-        internal_hashmap_free_free(HASHMAP_BASE(s));
-        return NULL;
+        return (Set*) internal_hashmap_free(HASHMAP_BASE(s), free, NULL);
 }
 
 /* no set_free_free_free */
@@ -76,11 +74,11 @@ static inline unsigned set_buckets(Set *s) {
 bool set_iterate(Set *s, Iterator *i, void **value);
 
 static inline void set_clear(Set *s) {
-        internal_hashmap_clear(HASHMAP_BASE(s));
+        internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
 }
 
 static inline void set_clear_free(Set *s) {
-        internal_hashmap_clear_free(HASHMAP_BASE(s));
+        internal_hashmap_clear(HASHMAP_BASE(s), free, NULL);
 }
 
 /* no set_clear_free_free */
index 470bde514528b14693b11ec19cd189b91cd81946..4ed19cd937573168550a4bdb2f22b0372b99495f 100644 (file)
@@ -39,7 +39,7 @@ int socket_address_listen(
 
         assert(a);
 
-        r = socket_address_verify(a);
+        r = socket_address_verify(a, true);
         if (r < 0)
                 return r;
 
index a1565665112d15f7b7837a7bb2a08c87651917a6..91bf801cdf26c470e2df03a2e27ab9eebf052e0e 100644 (file)
@@ -15,6 +15,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
@@ -111,7 +112,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
                 size_t l;
 
                 l = strlen(s+1);
-                if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminate sockets here
+                if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
                                                                * when parsing, even though abstract namespace sockets
                                                                * explicitly allow embedded NUL bytes and don't consider
                                                                * them special. But it's simply annoying to debug such
@@ -261,9 +262,12 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
         return 0;
 }
 
-int socket_address_verify(const SocketAddress *a) {
+int socket_address_verify(const SocketAddress *a, bool strict) {
         assert(a);
 
+        /* With 'strict' we enforce additional sanity constraints which are not set by the standard,
+         * but should only apply to sockets we create ourselves. */
+
         switch (socket_address_family(a)) {
 
         case AF_INET:
@@ -293,19 +297,20 @@ int socket_address_verify(const SocketAddress *a) {
         case AF_UNIX:
                 if (a->size < offsetof(struct sockaddr_un, sun_path))
                         return -EINVAL;
-                if (a->size > sizeof(struct sockaddr_un)+1) /* Allow one extra byte, since getsockname() on Linux will
-                                                             * append a NUL byte if we have path sockets that are above
-                                                             * sun_path' full size */
+                if (a->size > sizeof(struct sockaddr_un) + !strict)
+                        /* If !strict, allow one extra byte, since getsockname() on Linux will append
+                         * a NUL byte if we have path sockets that are above sun_path's full size. */
                         return -EINVAL;
 
                 if (a->size > offsetof(struct sockaddr_un, sun_path) &&
-                    a->sockaddr.un.sun_path[0] != 0) { /* Only validate file system sockets here */
-
+                    a->sockaddr.un.sun_path[0] != 0 &&
+                    strict) {
+                        /* Only validate file system sockets here, and only in strict mode */
                         const char *e;
 
                         e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
                         if (e) {
-                                /* If there's an embedded NUL byte, make sure the size of the socket addresses matches it */
+                                /* If there's an embedded NUL byte, make sure the size of the socket address matches it */
                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
                                         return -EINVAL;
                         } else {
@@ -353,7 +358,10 @@ int socket_address_print(const SocketAddress *a, char **ret) {
         assert(a);
         assert(ret);
 
-        r = socket_address_verify(a);
+        r = socket_address_verify(a, false); /* We do non-strict validation, because we want to be
+                                              * able to pretty-print any socket the kernel considers
+                                              * valid. We still need to do validation to know if we
+                                              * can meaningfully print the address. */
         if (r < 0)
                 return r;
 
@@ -386,8 +394,8 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
         assert(b);
 
         /* Invalid addresses are unequal to all */
-        if (socket_address_verify(a) < 0 ||
-            socket_address_verify(b) < 0)
+        if (socket_address_verify(a, false) < 0 ||
+            socket_address_verify(b, false) < 0)
                 return false;
 
         if (a->type != b->type)
@@ -571,7 +579,13 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
         }
 }
 
-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
+int sockaddr_pretty(
+                const struct sockaddr *_sa,
+                socklen_t salen,
+                bool translate_ipv6,
+                bool include_port,
+                char **ret) {
+
         union sockaddr_union *sa = (union sockaddr_union*) _sa;
         char *p;
         int r;
@@ -642,42 +656,51 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
         }
 
         case AF_UNIX:
-                if (salen <= offsetof(struct sockaddr_un, sun_path)) {
+                if (salen <= offsetof(struct sockaddr_un, sun_path) ||
+                    (sa->un.sun_path[0] == 0 && salen == offsetof(struct sockaddr_un, sun_path) + 1))
+                        /* The name must have at least one character (and the leading NUL does not count) */
                         p = strdup("<unnamed>");
-                        if (!p)
-                                return -ENOMEM;
-
-                } else if (sa->un.sun_path[0] == 0) {
-                        /* abstract */
-
-                        /* FIXME: We assume we can print the
-                         * socket path here and that it hasn't
-                         * more than one NUL byte. That is
-                         * actually an invalid assumption */
-
-                        p = new(char, sizeof(sa->un.sun_path)+1);
-                        if (!p)
-                                return -ENOMEM;
+                else {
+                        /* Note that we calculate the path pointer here through the .un_buffer[] field, in order to
+                         * outtrick bounds checking tools such as ubsan, which are too smart for their own good: on
+                         * Linux the kernel may return sun_path[] data one byte longer than the declared size of the
+                         * field. */
+                        char *path = (char*) sa->un_buffer + offsetof(struct sockaddr_un, sun_path);
+                        size_t path_len = salen - offsetof(struct sockaddr_un, sun_path);
+
+                        if (path[0] == 0) {
+                                /* Abstract socket. When parsing address information from, we
+                                 * explicitly reject overly long paths and paths with embedded NULs.
+                                 * But we might get such a socket from the outside. Let's return
+                                 * something meaningful and printable in this case. */
+
+                                _cleanup_free_ char *e = NULL;
+
+                                e = cescape_length(path + 1, path_len - 1);
+                                if (!e)
+                                        return -ENOMEM;
 
-                        p[0] = '@';
-                        memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
-                        p[sizeof(sa->un.sun_path)] = 0;
+                                p = strjoin("@", e);
+                        } else {
+                                if (path[path_len - 1] == '\0')
+                                        /* We expect a terminating NUL and don't print it */
+                                        path_len --;
 
-                } else {
-                        p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
-                        if (!p)
-                                return -ENOMEM;
+                                p = cescape_length(path, path_len);
+                        }
                 }
+                if (!p)
+                        return -ENOMEM;
 
                 break;
 
         case AF_VSOCK:
-                if (include_port)
-                        r = asprintf(&p,
-                                     "vsock:%u:%u",
-                                     sa->vm.svm_cid,
-                                     sa->vm.svm_port);
-                else
+                if (include_port) {
+                        if (sa->vm.svm_cid == VMADDR_CID_ANY)
+                                r = asprintf(&p, "vsock::%u", sa->vm.svm_port);
+                        else
+                                r = asprintf(&p, "vsock:%u:%u", sa->vm.svm_cid, sa->vm.svm_port);
+                else
                         r = asprintf(&p, "vsock:%u", sa->vm.svm_cid);
                 if (r < 0)
                         return -ENOMEM;
index 8090e21657e5c4d056f1550a5abb501a846ff78a..574d2b73f5627e8dc52194a8ac4cbd3996bfbad5 100644 (file)
@@ -1,6 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <inttypes.h>
+#include <linux/netlink.h>
+#include <linux/if_infiniband.h>
+#include <linux/if_packet.h>
 #include <netinet/ether.h>
 #include <netinet/in.h>
 #include <stdbool.h>
 #include <sys/socket.h>
 #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"
-#include "missing.h"
-#include "util.h"
+#include "missing_socket.h"
+#include "sparse-endian.h"
 
 union sockaddr_union {
         /* The minimal, abstract version */
@@ -70,7 +71,7 @@ int socket_address_parse(SocketAddress *a, const char *s);
 int socket_address_parse_and_warn(SocketAddress *a, const char *s);
 int socket_address_parse_netlink(SocketAddress *a, const char *s);
 int socket_address_print(const SocketAddress *a, char **p);
-int socket_address_verify(const SocketAddress *a) _pure_;
+int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
 
 int sockaddr_un_unlink(const struct sockaddr_un *sa);
 
index 3bef0dfe44fdfba8accd8958b729bc3d218c73f6..57700e2388a1b8e0d671c2ba8ed093f88181b30c 100644 (file)
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "missing.h"
+#include "parse-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 
@@ -296,3 +298,122 @@ int fd_verify_regular(int fd) {
 
         return stat_verify_regular(&st);
 }
+
+int stat_verify_directory(const struct stat *st) {
+        assert(st);
+
+        if (S_ISLNK(st->st_mode))
+                return -ELOOP;
+
+        if (!S_ISDIR(st->st_mode))
+                return -ENOTDIR;
+
+        return 0;
+}
+
+int fd_verify_directory(int fd) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        return stat_verify_directory(&st);
+}
+
+int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
+        const char *t;
+
+        /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
+
+        if (S_ISCHR(mode))
+                t = "char";
+        else if (S_ISBLK(mode))
+                t = "block";
+        else
+                return -ENODEV;
+
+        if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
+                return -ENOMEM;
+
+        return 0;
+
+}
+
+int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
+
+        assert(ret);
+
+        if (major(devno) == 0 && minor(devno) == 0) {
+                char *s;
+
+                /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
+                 * /dev/block/ and /dev/char/, hence we handle them specially here. */
+
+                if (S_ISCHR(mode))
+                        s = strdup("/run/systemd/inaccessible/chr");
+                else if (S_ISBLK(mode))
+                        s = strdup("/run/systemd/inaccessible/blk");
+                else
+                        return -ENODEV;
+
+                if (!s)
+                        return -ENOMEM;
+
+                *ret = s;
+                return 0;
+        }
+
+        r = device_path_make_major_minor(mode, devno, &p);
+        if (r < 0)
+                return r;
+
+        return chase_symlinks(p, NULL, 0, ret);
+}
+
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
+        mode_t mode;
+        dev_t devno;
+        int r;
+
+        /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
+         * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
+         * path cannot be parsed like this.  */
+
+        if (path_equal(path, "/run/systemd/inaccessible/chr")) {
+                mode = S_IFCHR;
+                devno = makedev(0, 0);
+        } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
+                mode = S_IFBLK;
+                devno = makedev(0, 0);
+        } else {
+                const char *w;
+
+                w = path_startswith(path, "/dev/block/");
+                if (w)
+                        mode = S_IFBLK;
+                else {
+                        w = path_startswith(path, "/dev/char/");
+                        if (!w)
+                                return -ENODEV;
+
+                        mode = S_IFCHR;
+                }
+
+                r = parse_dev(w, &devno);
+                if (r < 0)
+                        return r;
+        }
+
+        if (ret_mode)
+                *ret_mode = mode;
+        if (ret_devno)
+                *ret_devno = devno;
+
+        return 0;
+}
index 1a725f1da048409fd6c301cb0e8254c861a14245..0a08e642b54beab1c2282d69ce16a555c9053dcf 100644 (file)
@@ -59,3 +59,29 @@ int path_is_temporary_fs(const char *path);
 
 int stat_verify_regular(const struct stat *st);
 int fd_verify_regular(int fd);
+
+int stat_verify_directory(const struct stat *st);
+int fd_verify_directory(int fd);
+
+/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
+ * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
+ * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
+ * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
+ * such a test would be pointless in such a case.) */
+
+#define DEVICE_MAJOR_VALID(x)                                           \
+        ({                                                              \
+                typeof(x) _x = (x), _y = 0;                             \
+                _x >= _y && _x < (UINT32_C(1) << 12);                   \
+                                                                        \
+        })
+
+#define DEVICE_MINOR_VALID(x)                                           \
+        ({                                                              \
+                typeof(x) _x = (x), _y = 0;                             \
+                _x >= _y && _x < (UINT32_C(1) << 20);                   \
+        })
+
+int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
+int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
index cad838083fa7b1d792d4863354669d46643d660e..443c0e8ebb3b7b280ffbd8c877169d68a151dae5 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "alloc-util.h"
 #include "macro.h"
 
 /* A framework for registering static variables that shall be freed on shutdown of a process. It's a bit like gcc's
@@ -9,7 +10,7 @@
 
 typedef struct StaticDestructor {
         void *data;
-        void (*destroy)(void *p);
+        free_func_t destroy;
 } StaticDestructor;
 
 #define STATIC_DESTRUCTOR_REGISTER(variable, func) \
@@ -21,10 +22,14 @@ typedef struct StaticDestructor {
                 typeof(variable) *q = p;                                \
                 func(q);                                                \
         }                                                               \
-        /* The actual destructor structure */                           \
-        __attribute__ ((__section__("SYSTEMD_STATIC_DESTRUCT")))        \
-        __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)))            \
-        __attribute__ ((__used__))                                      \
+        /* The actual destructor structure we place in a special section to find it */ \
+        _section_("SYSTEMD_STATIC_DESTRUCT")                            \
+        /* We pick pointer alignment, since that is apparently what gcc does for static variables */ \
+        _alignptr_                                                      \
+        /* Make sure this is not dropped from the image because not explicitly referenced */ \
+        _used_                                                          \
+        /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section packed next to each other so that we can enumerate it. */ \
+        _variable_no_sanitize_address_                                  \
         static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \
                 .data = &(variable),                                    \
                 .destroy = UNIQ_T(static_destructor_wrapper, uq),       \
@@ -32,8 +37,8 @@ typedef struct StaticDestructor {
 
 /* Beginning and end of our section listing the destructors. We define these as weak as we want this to work even if
  * there's not a single destructor is defined in which case the section will be missing. */
-extern const struct StaticDestructor __attribute__((__weak__)) __start_SYSTEMD_STATIC_DESTRUCT[];
-extern const struct StaticDestructor __attribute__((__weak__)) __stop_SYSTEMD_STATIC_DESTRUCT[];
+extern const struct StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[];
+extern const struct StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[];
 
 /* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in the same
  * linking unit as the variables we want to destroy. */
@@ -43,9 +48,9 @@ static inline void static_destruct(void) {
         if (!__start_SYSTEMD_STATIC_DESTRUCT)
                 return;
 
-        d = ALIGN_TO_PTR(__start_SYSTEMD_STATIC_DESTRUCT, __BIGGEST_ALIGNMENT__);
+        d = ALIGN_TO_PTR(__start_SYSTEMD_STATIC_DESTRUCT, sizeof(void*));
         while (d < __stop_SYSTEMD_STATIC_DESTRUCT) {
                 d->destroy(d->data);
-                d = ALIGN_TO_PTR(d + 1, __BIGGEST_ALIGNMENT__);
+                d = ALIGN_TO_PTR(d + 1, sizeof(void*));
         }
 }
index a5e4de00b0818e49d910e5e817d2a633864d9528..ceba7d0ff85b8431fc0a92d77fda257bb6741815 100644 (file)
@@ -979,53 +979,56 @@ int get_ctty_devnr(pid_t pid, dev_t *d) {
         return 0;
 }
 
-int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
-        char fn[STRLEN("/dev/char/") + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
-        _cleanup_free_ char *s = NULL;
-        const char *p;
+int get_ctty(pid_t pid, dev_t *ret_devnr, char **ret) {
+        _cleanup_free_ char *fn = NULL, *b = NULL;
         dev_t devnr;
-        int k;
-
-        assert(r);
-
-        k = get_ctty_devnr(pid, &devnr);
-        if (k < 0)
-                return k;
-
-        sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
+        int r;
 
-        k = readlink_malloc(fn, &s);
-        if (k < 0) {
+        r = get_ctty_devnr(pid, &devnr);
+        if (r < 0)
+                return r;
 
-                if (k != -ENOENT)
-                        return k;
+        r = device_path_make_canonical(S_IFCHR, devnr, &fn);
+        if (r < 0) {
+                if (r != -ENOENT) /* No symlink for this in /dev/char/? */
+                        return r;
 
-                /* This is an ugly hack */
                 if (major(devnr) == 136) {
+                        /* This is an ugly hack: PTY devices are not listed in /dev/char/, as they don't follow the
+                         * Linux device model. This means we have no nice way to match them up against their actual
+                         * device node. Let's hence do the check by the fixed, assigned major number. Normally we try
+                         * to avoid such fixed major/minor matches, but there appears to nother nice way to handle
+                         * this. */
+
                         if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
                                 return -ENOMEM;
                 } else {
-                        /* Probably something like the ptys which have no
-                         * symlink in /dev/char. Let's return something
-                         * vaguely useful. */
+                        /* Probably something similar to the ptys which have no symlink in /dev/char/. Let's return
+                         * something vaguely useful. */
 
-                        b = strdup(fn + 5);
-                        if (!b)
-                                return -ENOMEM;
+                        r = device_path_make_major_minor(S_IFCHR, devnr, &fn);
+                        if (r < 0)
+                                return r;
                 }
-        } else {
-                p = PATH_STARTSWITH_SET(s, "/dev/", "../");
-                if (!p)
-                        p = s;
+        }
 
-                b = strdup(p);
-                if (!b)
-                        return -ENOMEM;
+        if (!b) {
+                const char *w;
+
+                w = path_startswith(fn, "/dev/");
+                if (w) {
+                        b = strdup(w);
+                        if (!b)
+                                return -ENOMEM;
+                } else
+                        b = TAKE_PTR(fn);
         }
 
-        *r = b;
-        if (_devnr)
-                *_devnr = devnr;
+        if (ret)
+                *ret = TAKE_PTR(b);
+
+        if (ret_devnr)
+                *ret_devnr = devnr;
 
         return 0;
 }
index 86e730028e4c1b7769cc0cf9e587f99d0d02bebe..c885e0a2d1a014dea069f46cf5e5e1d1537999e4 100644 (file)
@@ -18,6 +18,7 @@
 #define ANSI_MAGENTA "\x1B[0;35m"
 #define ANSI_CYAN    "\x1B[0;36m"
 #define ANSI_WHITE   "\x1B[0;37m"
+#define ANSI_GREY    "\x1B[0;2;37m"
 
 /* Bold/highlighted */
 #define ANSI_HIGHLIGHT_BLACK   "\x1B[0;1;30m"
@@ -132,6 +133,7 @@ DEFINE_ANSI_FUNC(highlight_yellow,           HIGHLIGHT_YELLOW);
 DEFINE_ANSI_FUNC(highlight_blue,             HIGHLIGHT_BLUE);
 DEFINE_ANSI_FUNC(highlight_magenta,          HIGHLIGHT_MAGENTA);
 DEFINE_ANSI_FUNC(normal,                     NORMAL);
+DEFINE_ANSI_FUNC(grey,                       GREY);
 
 DEFINE_ANSI_FUNC_UNDERLINE(underline,                  UNDERLINE, NORMAL);
 DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline,        HIGHLIGHT_UNDERLINE, HIGHLIGHT);
index f1f52f1beb057016d631cf05cf7ce10cb09f3029..557c75debc53ba264c37159fe4020ef11ce3ec30 100644 (file)
@@ -20,6 +20,7 @@
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing_timerfd.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
diff --git a/src/basic/tmpfile-util.c b/src/basic/tmpfile-util.c
new file mode 100644 (file)
index 0000000..dba0492
--- /dev/null
@@ -0,0 +1,329 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/mman.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "memfd-util.h"
+#include "missing_syscall.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "random-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "tmpfile-util.h"
+#include "umask-util.h"
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+        FILE *f;
+        char *t;
+        int r, fd;
+
+        assert(path);
+        assert(_f);
+        assert(_temp_path);
+
+        r = tempfn_xxxxxx(path, NULL, &t);
+        if (r < 0)
+                return r;
+
+        fd = mkostemp_safe(t);
+        if (fd < 0) {
+                free(t);
+                return -errno;
+        }
+
+        f = fdopen(fd, "we");
+        if (!f) {
+                unlink_noerrno(t);
+                free(t);
+                safe_close(fd);
+                return -errno;
+        }
+
+        *_f = f;
+        *_temp_path = t;
+
+        return 0;
+}
+
+/* This is much like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern) {
+        _cleanup_umask_ mode_t u = 0;
+        int fd;
+
+        assert(pattern);
+
+        u = umask(077);
+
+        fd = mkostemp(pattern, O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+
+int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
+        int fd;
+        FILE *f;
+
+        fd = mkostemp_safe(pattern);
+        if (fd < 0)
+                return fd;
+
+        f = fdopen(fd, mode);
+        if (!f) {
+                safe_close(fd);
+                return -errno;
+        }
+
+        *ret_f = f;
+        return 0;
+}
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
+        const char *fn;
+        char *t;
+
+        assert(ret);
+
+        if (isempty(p))
+                return -EINVAL;
+        if (path_equal(p, "/"))
+                return -EINVAL;
+
+        /*
+         * Turns this:
+         *         /foo/bar/waldo
+         *
+         * Into this:
+         *         /foo/bar/.#<extra>waldoXXXXXX
+         */
+
+        fn = basename(p);
+        if (!filename_is_valid(fn))
+                return -EINVAL;
+
+        extra = strempty(extra);
+
+        t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
+
+        *ret = path_simplify(t, false);
+        return 0;
+}
+
+int tempfn_random(const char *p, const char *extra, char **ret) {
+        const char *fn;
+        char *t, *x;
+        uint64_t u;
+        unsigned i;
+
+        assert(ret);
+
+        if (isempty(p))
+                return -EINVAL;
+        if (path_equal(p, "/"))
+                return -EINVAL;
+
+        /*
+         * Turns this:
+         *         /foo/bar/waldo
+         *
+         * Into this:
+         *         /foo/bar/.#<extra>waldobaa2a261115984a9
+         */
+
+        fn = basename(p);
+        if (!filename_is_valid(fn))
+                return -EINVAL;
+
+        extra = strempty(extra);
+
+        t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
+
+        u = random_u64();
+        for (i = 0; i < 16; i++) {
+                *(x++) = hexchar(u & 0xF);
+                u >>= 4;
+        }
+
+        *x = 0;
+
+        *ret = path_simplify(t, false);
+        return 0;
+}
+
+int tempfn_random_child(const char *p, const char *extra, char **ret) {
+        char *t, *x;
+        uint64_t u;
+        unsigned i;
+        int r;
+
+        assert(ret);
+
+        /* Turns this:
+         *         /foo/bar/waldo
+         * Into this:
+         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
+         */
+
+        if (!p) {
+                r = tmp_dir(&p);
+                if (r < 0)
+                        return r;
+        }
+
+        extra = strempty(extra);
+
+        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        if (isempty(p))
+                x = stpcpy(stpcpy(t, ".#"), extra);
+        else
+                x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
+
+        u = random_u64();
+        for (i = 0; i < 16; i++) {
+                *(x++) = hexchar(u & 0xF);
+                u >>= 4;
+        }
+
+        *x = 0;
+
+        *ret = path_simplify(t, false);
+        return 0;
+}
+
+int open_tmpfile_unlinkable(const char *directory, int flags) {
+        char *p;
+        int fd, r;
+
+        if (!directory) {
+                r = tmp_dir(&directory);
+                if (r < 0)
+                        return r;
+        } else if (isempty(directory))
+                return -EINVAL;
+
+        /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
+
+        /* Try O_TMPFILE first, if it is supported */
+        fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
+        if (fd >= 0)
+                return fd;
+
+        /* Fall back to unguessable name + unlinking */
+        p = strjoina(directory, "/systemd-tmp-XXXXXX");
+
+        fd = mkostemp_safe(p);
+        if (fd < 0)
+                return fd;
+
+        (void) unlink(p);
+
+        return fd;
+}
+
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
+        _cleanup_free_ char *tmp = NULL;
+        int r, fd;
+
+        assert(target);
+        assert(ret_path);
+
+        /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
+        assert((flags & O_EXCL) == 0);
+
+        /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
+         * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
+         * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
+
+        fd = open_parent(target, O_TMPFILE|flags, 0640);
+        if (fd >= 0) {
+                *ret_path = NULL;
+                return fd;
+        }
+
+        log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
+
+        r = tempfn_random(target, NULL, &tmp);
+        if (r < 0)
+                return r;
+
+        fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
+        if (fd < 0)
+                return -errno;
+
+        *ret_path = TAKE_PTR(tmp);
+
+        return fd;
+}
+
+int link_tmpfile(int fd, const char *path, const char *target) {
+        int r;
+
+        assert(fd >= 0);
+        assert(target);
+
+        /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
+         * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
+         * on the directory, and renameat2() is used instead.
+         *
+         * Note that in both cases we will not replace existing files. This is because linkat() does not support this
+         * operation currently (renameat2() does), and there is no nice way to emulate this. */
+
+        if (path) {
+                r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
+                if (r < 0)
+                        return r;
+        } else {
+                char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
+
+                xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
+
+                if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
+                        return -errno;
+        }
+
+        return 0;
+}
+
+int mkdtemp_malloc(const char *template, char **ret) {
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(ret);
+
+        if (template)
+                p = strdup(template);
+        else {
+                const char *tmp;
+
+                r = tmp_dir(&tmp);
+                if (r < 0)
+                        return r;
+
+                p = strjoin(tmp, "/XXXXXX");
+        }
+        if (!p)
+                return -ENOMEM;
+
+        if (!mkdtemp(p))
+                return -errno;
+
+        *ret = TAKE_PTR(p);
+        return 0;
+}
diff --git a/src/basic/tmpfile-util.h b/src/basic/tmpfile-util.h
new file mode 100644 (file)
index 0000000..802c85d
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdio.h>
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
+int mkostemp_safe(char *pattern);
+int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
+int tempfn_random(const char *p, const char *extra, char **ret);
+int tempfn_random_child(const char *p, const char *extra, char **ret);
+
+int open_tmpfile_unlinkable(const char *directory, int flags);
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
+
+int link_tmpfile(int fd, const char *path, const char *target);
+
+int mkdtemp_malloc(const char *template, char **ret);
index 61abcd585b11a48b7db836327e49620b8df298e0..d373f03aca59ee6ac8cb23803ff12b6588f0b2c9 100644 (file)
@@ -61,5 +61,5 @@ static inline int unit_name_mangle(const char *name, UnitNameMangle flags, char
 }
 
 int slice_build_parent_slice(const char *slice, char **ret);
-int slice_build_subslice(const char *slice, const char*name, char **subslice);
+int slice_build_subslice(const char *slice, const char *name, char **subslice);
 bool slice_name_is_valid(const char *name);
index 3de798050d6f89d0b9bb01246326518b7efcf981..628456936eb31b3a9ba972d0e5473f85ec41a4b9 100644 (file)
@@ -7,7 +7,7 @@
 #include <uchar.h>
 
 #include "macro.h"
-#include "missing.h"
+#include "missing_type.h"
 
 #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
 #define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf"
index 00052c5e1dea00417e35c3da7a42fa833e2ea83d..c4f12a6daa052751576de06b65aac1220debe338 100644 (file)
@@ -23,6 +23,7 @@
 #include "def.h"
 #include "device-nodes.h"
 #include "dirent-util.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
index 2f3d1eeab86a03bfc8092d9683597f70df98b56a..01118bb895477bc1d6d2d69a892361a31f37e158 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "format-util.h"
 #include "macro.h"
-#include "missing.h"
 #include "time-util.h"
 
 size_t page_size(void) _pure_;
@@ -173,7 +172,7 @@ static inline void _reset_errno_(int *saved_errno) {
 }
 
 #define PROTECT_ERRNO                                                   \
-        _cleanup_(_reset_errno_) __attribute__((__unused__)) int _saved_errno_ = errno
+        _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
 
 static inline int negative_errno(void) {
         /* This helper should be used to shut up gcc if you know 'errno' is
index 608b35b7158981ad7cfd94e68902161e50823b8e..2008341f631e1132ca6c008195625809cd917c1b 100644 (file)
@@ -38,6 +38,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "umask-util.h"
 #include "utf8.h"
 #include "util.h"
index b8c8070341eb280f00ca28a198a0cf4f08d641d7..243c80a8352434d73fb64c82a1f6594a526bb7c7 100644 (file)
@@ -132,13 +132,13 @@ typedef struct {
         UINT16 HeaderVersion;
         UINT32 PCRIndex;
         UINT32 EventType;
-} __attribute__ ((packed)) EFI_TCG2_EVENT_HEADER;
+} __attribute__((packed)) EFI_TCG2_EVENT_HEADER;
 
 typedef struct tdEFI_TCG2_EVENT {
         UINT32 Size;
         EFI_TCG2_EVENT_HEADER Header;
         UINT8 Event[1];
-} __attribute__ ((packed)) EFI_TCG2_EVENT;
+} __attribute__((packed)) EFI_TCG2_EVENT;
 
 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This,
                                                       IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability);
@@ -346,7 +346,6 @@ EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UIN
                 else
                         log_fmt = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
 
-                uefi_call_wrapper(BS->Stall, 1, 2000 * 1000);
                 return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description, log_fmt);
         }
 
index 73ff861cb6f6618bc1217b6c15c12533e7a929d4..f6ffed143cd8eb226d969d2d2402e6852a7decf4 100644 (file)
@@ -205,35 +205,3 @@ EFI_STATUS security_policy_install(void) {
 
         return EFI_SUCCESS;
 }
-
-EFI_STATUS security_policy_uninstall(void) {
-        EFI_STATUS status;
-
-        if (esfas) {
-                EFI_SECURITY_PROTOCOL *security_protocol;
-
-                status = uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &security_protocol_guid, NULL, (VOID**) &security_protocol);
-
-                if (status != EFI_SUCCESS)
-                        return status;
-
-                security_protocol->FileAuthenticationState = esfas;
-                esfas = NULL;
-        } else
-                /* nothing installed */
-                return EFI_NOT_STARTED;
-
-        if (es2fa) {
-                EFI_SECURITY2_PROTOCOL *security2_protocol;
-
-                status = uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &security2_protocol_guid, NULL, (VOID**) &security2_protocol);
-
-                if (status != EFI_SUCCESS)
-                        return status;
-
-                security2_protocol->FileAuthentication = es2fa;
-                es2fa = NULL;
-        }
-
-        return EFI_SUCCESS;
-}
index 6b3b78c175019aac10d83e7a88f6ae516b93c9a7..209c9d4cf051c95b95f69892c177ab578d19566d 100644 (file)
@@ -14,5 +14,3 @@ BOOLEAN shim_loaded(void);
 BOOLEAN secure_boot_enabled(void);
 
 EFI_STATUS security_policy_install(void);
-
-EFI_STATUS security_policy_uninstall(void);
index 1b0939cabafd9e9cc74eb557976044c45ba19b63..0bcc89f6f26df2adf53546064af0f2ecfb5ba19f 100644 (file)
@@ -713,8 +713,7 @@ typedef struct Member {
         uint64_t flags;
 } Member;
 
-static void member_hash_func(const void *p, struct siphash *state) {
-        const Member *m = p;
+static void member_hash_func(const Member *m, struct siphash *state) {
         uint64_t arity = 1;
 
         assert(m);
@@ -921,12 +920,9 @@ static int on_property(const char *interface, const char *name, const char *sign
         return 0;
 }
 
-static int introspect(int argc, char **argv, void *userdata) {
-        static const struct hash_ops member_hash_ops = {
-                .hash = member_hash_func,
-                .compare = (__compar_fn_t) member_compare_func,
-        };
+DEFINE_PRIVATE_HASH_OPS(member_hash_ops, Member, member_hash_func, member_compare_func);
 
+static int introspect(int argc, char **argv, void *userdata) {
         static const XMLIntrospectOps ops = {
                 .on_interface = on_interface,
                 .on_method = on_method,
@@ -1943,7 +1939,7 @@ static void json_dump_with_flags(JsonVariant *v, FILE *f) {
 
         json_variant_dump(v,
                           (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) |
-                          colors_enabled() * JSON_FORMAT_COLOR,
+                          JSON_FORMAT_COLOR_AUTO,
                           f, NULL);
 }
 
index 5f6e778a382b00f82f7c6eff5281fd9c2f123a62..5abfab03de5416511e8c47563c61a15ec5e1d73f 100644 (file)
@@ -84,24 +84,14 @@ static enum {
         CPU_TIME,
 } arg_cpu_type = CPU_PERCENT;
 
-static void group_free(Group *g) {
-        assert(g);
+static Group *group_free(Group *g) {
+        if (!g)
+                return NULL;
 
         free(g->path);
-        free(g);
+        return mfree(g);
 }
 
-static void group_hashmap_clear(Hashmap *h) {
-        hashmap_clear_with_destructor(h, group_free);
-}
-
-static void group_hashmap_free(Hashmap *h) {
-        group_hashmap_clear(h);
-        hashmap_free(h);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, group_hashmap_free);
-
 static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
         if (!is_valid)
                 return "-";
@@ -908,8 +898,10 @@ static const char* counting_what(void) {
                 return "userspace processes (excl. kernel)";
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(group_hash_ops, char, path_hash_func, path_compare_func, Group, group_free);
+
 static int run(int argc, char *argv[]) {
-        _cleanup_(group_hashmap_freep) Hashmap *a = NULL, *b = NULL;
+        _cleanup_hashmap_free_ Hashmap *a = NULL, *b = NULL;
         unsigned iteration = 0;
         usec_t last_refresh = 0;
         bool quit = false, immediate_refresh = false;
@@ -940,8 +932,8 @@ static int run(int argc, char *argv[]) {
                 return log_error_errno(r, "Failed to get root control group path: %m");
         log_debug("Cgroup path: %s", root);
 
-        a = hashmap_new(&path_hash_ops);
-        b = hashmap_new(&path_hash_ops);
+        a = hashmap_new(&group_hash_ops);
+        b = hashmap_new(&group_hash_ops);
         if (!a || !b)
                 return log_oom();
 
@@ -951,7 +943,6 @@ static int run(int argc, char *argv[]) {
                 arg_iterations = on_tty() ? 0 : 1;
 
         while (!quit) {
-                Hashmap *c;
                 usec_t t;
                 char key;
                 char h[FORMAT_TIMESPAN_MAX];
@@ -964,11 +955,8 @@ static int run(int argc, char *argv[]) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to refresh: %m");
 
-                        group_hashmap_clear(b);
-
-                        c = a;
-                        a = b;
-                        b = c;
+                        hashmap_clear(b);
+                        SWAP_TWO(a, b);
 
                         last_refresh = t;
                         immediate_refresh = false;
index 5c1748542e294b25ebda58cfedfb80528e2a4c3e..de8010bf2e5d86865cb7fff98033423713959e77 100644 (file)
@@ -16,6 +16,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "dbus-automount.h"
+#include "dbus-unit.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "io-util.h"
@@ -23,6 +24,7 @@
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mount.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -236,6 +238,9 @@ static void automount_set_state(Automount *a, AutomountState state) {
         AutomountState old_state;
         assert(a);
 
+        if (a->state != state)
+                bus_unit_send_pending_change_signal(UNIT(a), false);
+
         old_state = a->state;
         a->state = state;
 
index d8915244a7a28aab8a6b453133febe60731cf7ab..dade7f04906a64a7fc898d5d2314934e8f308212 100644 (file)
@@ -84,6 +84,32 @@ int cgroup_bpf_whitelist_major(BPFProgram *prog, int type, int major, const char
         return r;
 }
 
+int cgroup_bpf_whitelist_class(BPFProgram *prog, int type, const char *acc) {
+        struct bpf_insn insn[] = {
+                BPF_JMP_IMM(BPF_JNE, BPF_REG_2, type, 5), /* compare device type */
+                BPF_MOV32_REG(BPF_REG_1, BPF_REG_3), /* calculate access type */
+                BPF_ALU32_IMM(BPF_AND, BPF_REG_1, 0),
+                BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 1), /* compare access type */
+                BPF_JMP_A(PASS_JUMP_OFF), /* jump to PASS */
+        };
+        int r, access;
+
+        assert(prog);
+        assert(acc);
+
+        access = bpf_access_type(acc);
+        if (access <= 0)
+                return -EINVAL;
+
+        insn[2].imm = access;
+
+        r = bpf_program_add_instructions(prog, insn, ELEMENTSOF(insn));
+        if (r < 0)
+                log_error_errno(r, "Extending device control BPF program failed: %m");
+
+        return r;
+}
+
 int cgroup_init_device_bpf(BPFProgram **ret, CGroupDevicePolicy policy, bool whitelist) {
         struct bpf_insn pre_insn[] = {
                 /* load device type to r2 */
index f9a6eec028dd482ec66e463a4bd3a359320d4c5b..8d3de3bd9407fdd0c87655a0000f84bd5221c62f 100644 (file)
@@ -11,6 +11,7 @@ int bpf_devices_supported(void);
 
 int cgroup_bpf_whitelist_device(BPFProgram *p, int type, int major, int minor, const char *acc);
 int cgroup_bpf_whitelist_major(BPFProgram *p, int type, int major, const char *acc);
+int cgroup_bpf_whitelist_class(BPFProgram *prog, int type, const char *acc);
 
 int cgroup_init_device_bpf(BPFProgram **ret, CGroupDevicePolicy policy, bool whitelist);
 int cgroup_apply_device_bpf(Unit *u, BPFProgram *p, CGroupDevicePolicy policy, bool whitelist);
index 946c0516e142effb7a2abbffaa3421deb2a31a93..b9a611fd9e25194eeb3c53d9c3341c91a4a53009 100644 (file)
@@ -20,6 +20,7 @@
 #include "bpf-program.h"
 #include "fd-util.h"
 #include "ip-address-access.h"
+#include "missing_syscall.h"
 #include "unit.h"
 
 enum {
index 598b396186b83b6d0080e5d8b3e2e4d916a0a47f..2dd53191e0744b5e0b3e4b0bf50820b2a3973ebe 100644 (file)
@@ -19,6 +19,7 @@
 #include "process-util.h"
 #include "procfs-util.h"
 #include "special.h"
+#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -374,17 +375,44 @@ int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode)
         return 0;
 }
 
+static void cgroup_xattr_apply(Unit *u) {
+        char ids[SD_ID128_STRING_MAX];
+        int r;
+
+        assert(u);
+
+        if (!MANAGER_IS_SYSTEM(u->manager))
+                return;
+
+        if (sd_id128_is_null(u->invocation_id))
+                return;
+
+        r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
+                         "trusted.invocation_id",
+                         sd_id128_to_string(u->invocation_id, ids), 32,
+                         0);
+        if (r < 0)
+                log_unit_debug_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path);
+}
+
 static int lookup_block_device(const char *p, dev_t *ret) {
-        struct stat st;
+        struct stat st = {};
         int r;
 
         assert(p);
         assert(ret);
 
-        if (stat(p, &st) < 0)
-                return log_warning_errno(errno, "Couldn't stat device '%s': %m", p);
-
-        if (S_ISBLK(st.st_mode))
+        r = device_path_parse_major_minor(p, &st.st_mode, &st.st_rdev);
+        if (r == -ENODEV) { /* not a parsable device node, need to go to disk */
+                if (stat(p, &st) < 0)
+                        return log_warning_errno(errno, "Couldn't stat device '%s': %m", p);
+        } else if (r < 0)
+                return log_warning_errno(r, "Failed to parse major/minor from path '%s': %m", p);
+
+        if (S_ISCHR(st.st_mode)) {
+                log_warning("Device node '%s' is a character device, but block device needed.", p);
+                return -ENOTBLK;
+        } else if (S_ISBLK(st.st_mode))
                 *ret = st.st_rdev;
         else if (major(st.st_dev) != 0)
                 *ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */
@@ -408,30 +436,27 @@ static int lookup_block_device(const char *p, dev_t *ret) {
 }
 
 static int whitelist_device(BPFProgram *prog, const char *path, const char *node, const char *acc) {
-        struct stat st;
-        bool ignore_notfound;
+        struct stat st = {};
         int r;
 
         assert(path);
         assert(acc);
 
-        if (node[0] == '-') {
-                /* Non-existent paths starting with "-" must be silently ignored */
-                node++;
-                ignore_notfound = true;
-        } else
-                ignore_notfound = false;
-
-        if (stat(node, &st) < 0) {
-                if (errno == ENOENT && ignore_notfound)
-                        return 0;
+        /* Some special handling for /dev/block/%u:%u, /dev/char/%u:%u, /run/systemd/inaccessible/chr and
+         * /run/systemd/inaccessible/blk paths. Instead of stat()ing these we parse out the major/minor directly. This
+         * means clients can use these path without the device node actually around */
+        r = device_path_parse_major_minor(node, &st.st_mode, &st.st_rdev);
+        if (r < 0) {
+                if (r != -ENODEV)
+                        return log_warning_errno(r, "Couldn't parse major/minor from device path '%s': %m", node);
 
-                return log_warning_errno(errno, "Couldn't stat device %s: %m", node);
-        }
+                if (stat(node, &st) < 0)
+                        return log_warning_errno(errno, "Couldn't stat device %s: %m", node);
 
-        if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
-                log_warning("%s is not a device.", node);
-                return -ENODEV;
+                if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
+                        log_warning("%s is not a device.", node);
+                        return -ENODEV;
+                }
         }
 
         if (cg_all_unified() > 0) {
@@ -463,21 +488,64 @@ static int whitelist_device(BPFProgram *prog, const char *path, const char *node
 
 static int whitelist_major(BPFProgram *prog, const char *path, const char *name, char type, const char *acc) {
         _cleanup_fclose_ FILE *f = NULL;
-        char *p, *w;
+        char buf[2+DECIMAL_STR_MAX(unsigned)+3+4];
         bool good = false;
+        unsigned maj;
         int r;
 
         assert(path);
         assert(acc);
         assert(IN_SET(type, 'b', 'c'));
 
+        if (streq(name, "*")) {
+                /* If the name is a wildcard, then apply this list to all devices of this type */
+
+                if (cg_all_unified() > 0) {
+                        if (!prog)
+                                return 0;
+
+                        (void) cgroup_bpf_whitelist_class(prog, type == 'c' ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK, acc);
+                } else {
+                        xsprintf(buf, "%c *:* %s", type, acc);
+
+                        r = cg_set_attribute("devices", path, "devices.allow", buf);
+                        if (r < 0)
+                                log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                                               "Failed to set devices.allow on %s: %m", path);
+                        return 0;
+                }
+        }
+
+        if (safe_atou(name, &maj) >= 0 && DEVICE_MAJOR_VALID(maj)) {
+                /* The name is numeric and suitable as major. In that case, let's take is major, and create the entry
+                 * directly */
+
+                if (cg_all_unified() > 0) {
+                        if (!prog)
+                                return 0;
+
+                        (void) cgroup_bpf_whitelist_major(prog,
+                                                          type == 'c' ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK,
+                                                          maj, acc);
+                } else {
+                        xsprintf(buf, "%c %u:* %s", type, maj, acc);
+
+                        r = cg_set_attribute("devices", path, "devices.allow", buf);
+                        if (r < 0)
+                                log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                                               "Failed to set devices.allow on %s: %m", path);
+                }
+
+                return 0;
+        }
+
         f = fopen("/proc/devices", "re");
         if (!f)
                 return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type);
 
         for (;;) {
                 _cleanup_free_ char *line = NULL;
-                unsigned maj;
+                char *w, *p;
 
                 r = read_line(f, LONG_LINE_MAX, &line);
                 if (r < 0)
@@ -530,8 +598,6 @@ static int whitelist_major(BPFProgram *prog, const char *path, const char *name,
                                                           type == 'c' ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK,
                                                           maj, acc);
                 } else {
-                        char buf[2+DECIMAL_STR_MAX(unsigned)+3+4];
-
                         sprintf(buf,
                                 "%c %u:* %s",
                                 type,
@@ -809,68 +875,53 @@ static void cgroup_context_apply(
         if (is_local_root) /* Make sure we don't try to display messages with an empty path. */
                 path = "/";
 
-        /* We generally ignore errors caused by read-only mounted
-         * cgroup trees (assuming we are running in a container then),
-         * and missing cgroups, i.e. EROFS and ENOENT. */
-
-        if (apply_mask & CGROUP_MASK_CPU) {
-                bool has_weight, has_shares;
+        /* We generally ignore errors caused by read-only mounted cgroup trees (assuming we are running in a container
+         * then), and missing cgroups, i.e. EROFS and ENOENT. */
 
-                has_weight = cgroup_context_has_cpu_weight(c);
-                has_shares = cgroup_context_has_cpu_shares(c);
+        /* In fully unified mode these attributes don't exist on the host cgroup root. On legacy the weights exist, but
+         * setting the weight makes very little sense on the host root cgroup, as there are no other cgroups at this
+         * level. The quota exists there too, but any attempt to write to it is refused with EINVAL. Inside of
+         * containers we want to leave control of these to the container manager (and if cgroupsv2 delegation is used
+         * we couldn't even write to them if we wanted to). */
+        if ((apply_mask & CGROUP_MASK_CPU) && !is_local_root) {
 
                 if (cg_all_unified() > 0) {
+                        uint64_t weight;
 
-                        /* In fully unified mode these attributes don't exist on the host cgroup root, and inside of
-                         * containers we want to leave control of these to the container manager (and if delegation is
-                         * used we couldn't even write to them if we wanted to). */
-                        if (!is_local_root) {
-                                uint64_t weight;
-
-                                if (has_weight)
-                                        weight = cgroup_context_cpu_weight(c, state);
-                                else if (has_shares) {
-                                        uint64_t shares;
+                        if (cgroup_context_has_cpu_weight(c))
+                                weight = cgroup_context_cpu_weight(c, state);
+                        else if (cgroup_context_has_cpu_shares(c)) {
+                                uint64_t shares;
 
-                                        shares = cgroup_context_cpu_shares(c, state);
-                                        weight = cgroup_cpu_shares_to_weight(shares);
+                                shares = cgroup_context_cpu_shares(c, state);
+                                weight = cgroup_cpu_shares_to_weight(shares);
 
-                                        log_cgroup_compat(u, "Applying [Startup]CPUShares %" PRIu64 " as [Startup]CPUWeight %" PRIu64 " on %s",
-                                                          shares, weight, path);
-                                } else
-                                        weight = CGROUP_WEIGHT_DEFAULT;
+                                log_cgroup_compat(u, "Applying [Startup]CPUShares=%" PRIu64 " as [Startup]CPUWeight=%" PRIu64 " on %s",
+                                                  shares, weight, path);
+                        } else
+                                weight = CGROUP_WEIGHT_DEFAULT;
 
-                                cgroup_apply_unified_cpu_weight(u, weight);
-                                cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec);
-                        }
+                        cgroup_apply_unified_cpu_weight(u, weight);
+                        cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec);
 
                 } else {
-                        /* Setting the weight makes very little sense on the host root cgroup, as there are no other
-                         * cgroups at this level. And for containers we want to leave management of this to the
-                         * container manager */
-                        if (!is_local_root) {
-                                uint64_t shares;
-
-                                if (has_weight) {
-                                        uint64_t weight;
+                        uint64_t shares;
 
-                                        weight = cgroup_context_cpu_weight(c, state);
-                                        shares = cgroup_cpu_weight_to_shares(weight);
+                        if (cgroup_context_has_cpu_weight(c)) {
+                                uint64_t weight;
 
-                                        log_cgroup_compat(u, "Applying [Startup]CPUWeight %" PRIu64 " as [Startup]CPUShares %" PRIu64 " on %s",
-                                                          weight, shares, path);
-                                } else if (has_shares)
-                                        shares = cgroup_context_cpu_shares(c, state);
-                                else
-                                        shares = CGROUP_CPU_SHARES_DEFAULT;
+                                weight = cgroup_context_cpu_weight(c, state);
+                                shares = cgroup_cpu_weight_to_shares(weight);
 
-                                cgroup_apply_legacy_cpu_shares(u, shares);
-                        }
+                                log_cgroup_compat(u, "Applying [Startup]CPUWeight=%" PRIu64 " as [Startup]CPUShares=%" PRIu64 " on %s",
+                                                  weight, shares, path);
+                        } else if (cgroup_context_has_cpu_shares(c))
+                                shares = cgroup_context_cpu_shares(c, state);
+                        else
+                                shares = CGROUP_CPU_SHARES_DEFAULT;
 
-                        /* The "cpu" quota attribute is available on the host root, hence manage it there. But in
-                         * containers let's leave this to the container manager. */
-                        if (is_host_root || !is_local_root)
-                                cgroup_apply_legacy_cpu_quota(u, c->cpu_quota_per_sec_usec);
+                        cgroup_apply_legacy_cpu_shares(u, shares);
+                        cgroup_apply_legacy_cpu_quota(u, c->cpu_quota_per_sec_usec);
                 }
         }
 
@@ -893,7 +944,7 @@ static void cgroup_context_apply(
                         blkio_weight = cgroup_context_blkio_weight(c, state);
                         weight = cgroup_weight_blkio_to_io(blkio_weight);
 
-                        log_cgroup_compat(u, "Applying [Startup]BlockIOWeight %" PRIu64 " as [Startup]IOWeight %" PRIu64,
+                        log_cgroup_compat(u, "Applying [Startup]BlockIOWeight=%" PRIu64 " as [Startup]IOWeight=%" PRIu64,
                                           blkio_weight, weight);
                 } else
                         weight = CGROUP_WEIGHT_DEFAULT;
@@ -922,7 +973,7 @@ static void cgroup_context_apply(
                         LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
                                 weight = cgroup_weight_blkio_to_io(w->weight);
 
-                                log_cgroup_compat(u, "Applying BlockIODeviceWeight %" PRIu64 " as IODeviceWeight %" PRIu64 " for %s",
+                                log_cgroup_compat(u, "Applying BlockIODeviceWeight=%" PRIu64 " as IODeviceWeight=%" PRIu64 " for %s",
                                                   w->weight, weight, w->path);
 
                                 cgroup_apply_io_device_weight(u, w->path, weight);
@@ -938,7 +989,7 @@ static void cgroup_context_apply(
                                 limits[CGROUP_IO_RBPS_MAX] = b->rbps;
                                 limits[CGROUP_IO_WBPS_MAX] = b->wbps;
 
-                                log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax for %s",
+                                log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth=%" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax= for %s",
                                                   b->rbps, b->wbps, b->path);
 
                                 cgroup_apply_io_device_limit(u, b->path, limits);
@@ -964,7 +1015,7 @@ static void cgroup_context_apply(
                                 io_weight = cgroup_context_io_weight(c, state);
                                 weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state));
 
-                                log_cgroup_compat(u, "Applying [Startup]IOWeight %" PRIu64 " as [Startup]BlockIOWeight %" PRIu64,
+                                log_cgroup_compat(u, "Applying [Startup]IOWeight=%" PRIu64 " as [Startup]BlockIOWeight=%" PRIu64,
                                                   io_weight, weight);
                         } else if (has_blockio)
                                 weight = cgroup_context_blkio_weight(c, state);
@@ -980,7 +1031,7 @@ static void cgroup_context_apply(
                                 LIST_FOREACH(device_weights, w, c->io_device_weights) {
                                         weight = cgroup_weight_io_to_blkio(w->weight);
 
-                                        log_cgroup_compat(u, "Applying IODeviceWeight %" PRIu64 " as BlockIODeviceWeight %" PRIu64 " for %s",
+                                        log_cgroup_compat(u, "Applying IODeviceWeight=%" PRIu64 " as BlockIODeviceWeight=%" PRIu64 " for %s",
                                                           w->weight, weight, w->path);
 
                                         cgroup_apply_blkio_device_weight(u, w->path, weight);
@@ -1000,7 +1051,7 @@ static void cgroup_context_apply(
                                 CGroupIODeviceLimit *l;
 
                                 LIST_FOREACH(device_limits, l, c->io_device_limits) {
-                                        log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax for %s",
+                                        log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth=%" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax= for %s",
                                                           l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX], l->path);
 
                                         cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]);
@@ -1014,56 +1065,51 @@ static void cgroup_context_apply(
                 }
         }
 
-        if (apply_mask & CGROUP_MASK_MEMORY) {
+        /* In unified mode 'memory' attributes do not exist on the root cgroup. In legacy mode 'memory.limit_in_bytes'
+         * exists on the root cgroup, but any writes to it are refused with EINVAL. And if we run in a container we
+         * want to leave control to the container manager (and if proper cgroupsv2 delegation is used we couldn't even
+         * write to this if we wanted to.) */
+        if ((apply_mask & CGROUP_MASK_MEMORY) && !is_local_root) {
 
                 if (cg_all_unified() > 0) {
-                        /* In unified mode 'memory' attributes do not exist on the root cgroup. And if we run in a
-                         * container we want to leave control to the container manager (and if proper delegation is
-                         * used we couldn't even write to this if we wanted to. */
-                        if (!is_local_root) {
-                                uint64_t max, swap_max = CGROUP_LIMIT_MAX;
-
-                                if (cgroup_context_has_unified_memory_config(c)) {
-                                        max = c->memory_max;
-                                        swap_max = c->memory_swap_max;
-                                } else {
-                                        max = c->memory_limit;
-
-                                        if (max != CGROUP_LIMIT_MAX)
-                                                log_cgroup_compat(u, "Applying MemoryLimit=%" PRIu64 " as MemoryMax=", max);
-                                }
+                        uint64_t max, swap_max = CGROUP_LIMIT_MAX;
+
+                        if (cgroup_context_has_unified_memory_config(c)) {
+                                max = c->memory_max;
+                                swap_max = c->memory_swap_max;
+                        } else {
+                                max = c->memory_limit;
 
-                                cgroup_apply_unified_memory_limit(u, "memory.min", c->memory_min);
-                                cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low);
-                                cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
-                                cgroup_apply_unified_memory_limit(u, "memory.max", max);
-                                cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max);
+                                if (max != CGROUP_LIMIT_MAX)
+                                        log_cgroup_compat(u, "Applying MemoryLimit=%" PRIu64 " as MemoryMax=", max);
                         }
-                } else {
 
-                        /* In legacy mode 'memory' exists on the host root, but in container mode we want to leave it
-                         * to the container manager around us */
-                        if (is_host_root || !is_local_root) {
-                                char buf[DECIMAL_STR_MAX(uint64_t) + 1];
-                                uint64_t val;
+                        cgroup_apply_unified_memory_limit(u, "memory.min", c->memory_min);
+                        cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low);
+                        cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
+                        cgroup_apply_unified_memory_limit(u, "memory.max", max);
+                        cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max);
 
-                                if (cgroup_context_has_unified_memory_config(c)) {
-                                        val = c->memory_max;
-                                        log_cgroup_compat(u, "Applying MemoryMax=%" PRIi64 " as MemoryLimit=", val);
-                                } else
-                                        val = c->memory_limit;
+                } else {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+                        uint64_t val;
 
-                                if (val == CGROUP_LIMIT_MAX)
-                                        strncpy(buf, "-1\n", sizeof(buf));
-                                else
-                                        xsprintf(buf, "%" PRIu64 "\n", val);
+                        if (cgroup_context_has_unified_memory_config(c)) {
+                                val = c->memory_max;
+                                log_cgroup_compat(u, "Applying MemoryMax=%" PRIi64 " as MemoryLimit=", val);
+                        } else
+                                val = c->memory_limit;
 
-                                (void) set_attribute_and_warn(u, "memory", "memory.limit_in_bytes", buf);
-                        }
+                        if (val == CGROUP_LIMIT_MAX)
+                                strncpy(buf, "-1\n", sizeof(buf));
+                        else
+                                xsprintf(buf, "%" PRIu64 "\n", val);
+
+                        (void) set_attribute_and_warn(u, "memory", "memory.limit_in_bytes", buf);
                 }
         }
 
-        /* On cgroupsv2 we can apply BPF everywhre. On cgroupsv1 we apply it everywhere except for the root of
+        /* On cgroupsv2 we can apply BPF everywhere. On cgroupsv1 we apply it everywhere except for the root of
          * containers, where we leave this to the manager */
         if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) &&
             (is_host_root || cg_all_unified() > 0 || !is_local_root)) {
@@ -1098,8 +1144,8 @@ static void cgroup_context_apply(
                                 "/dev/tty\0" "rwm\0"
                                 "/dev/ptmx\0" "rwm\0"
                                 /* Allow /run/systemd/inaccessible/{chr,blk} devices for mapping InaccessiblePaths */
-                                "-/run/systemd/inaccessible/chr\0" "rwm\0"
-                                "-/run/systemd/inaccessible/blk\0" "rwm\0";
+                                "/run/systemd/inaccessible/chr\0" "rwm\0"
+                                "/run/systemd/inaccessible/blk\0" "rwm\0";
 
                         const char *x, *y;
 
@@ -1133,7 +1179,7 @@ static void cgroup_context_apply(
                         else if ((val = startswith(a->path, "char-")))
                                 (void) whitelist_major(prog, path, val, 'c', acc);
                         else
-                                log_unit_debug(u, "Ignoring device %s while writing cgroup attribute.", a->path);
+                                log_unit_debug(u, "Ignoring device '%s' while writing cgroup attribute.", a->path);
                 }
 
                 r = cgroup_apply_device_bpf(u, prog, c->device_policy, c->device_allow);
@@ -1172,7 +1218,6 @@ static void cgroup_context_apply(
                                 r = procfs_tasks_set_limit(TASKS_MAX);
                         else
                                 r = 0;
-
                         if (r < 0)
                                 log_unit_full(u, LOG_LEVEL_CGROUP_WRITE(r), r,
                                               "Failed to write to tasks limit sysctls: %m");
@@ -1280,7 +1325,7 @@ CGroupMask unit_get_own_mask(Unit *u) {
         if (!c)
                 return 0;
 
-        return cgroup_context_get_mask(c) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u);
+        return (cgroup_context_get_mask(c) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u)) & ~unit_get_ancestor_disable_mask(u);
 }
 
 CGroupMask unit_get_delegate_mask(Unit *u) {
@@ -1350,6 +1395,31 @@ CGroupMask unit_get_siblings_mask(Unit *u) {
         return unit_get_subtree_mask(u); /* we are the top-level slice */
 }
 
+CGroupMask unit_get_disable_mask(Unit *u) {
+        CGroupContext *c;
+
+        c = unit_get_cgroup_context(u);
+        if (!c)
+                return 0;
+
+        return c->disable_controllers;
+}
+
+CGroupMask unit_get_ancestor_disable_mask(Unit *u) {
+        CGroupMask mask;
+
+        assert(u);
+        mask = unit_get_disable_mask(u);
+
+        /* Returns the mask of controllers which are marked as forcibly
+         * disabled in any ancestor unit or the unit in question. */
+
+        if (UNIT_ISSET(u->slice))
+                mask |= unit_get_ancestor_disable_mask(UNIT_DEREF(u->slice));
+
+        return mask;
+}
+
 CGroupMask unit_get_subtree_mask(Unit *u) {
 
         /* Returns the mask of this subtree, meaning of the group
@@ -1370,6 +1440,7 @@ CGroupMask unit_get_target_mask(Unit *u) {
 
         mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
         mask &= u->manager->cgroup_supported;
+        mask &= ~unit_get_ancestor_disable_mask(u);
 
         return mask;
 }
@@ -1384,6 +1455,7 @@ CGroupMask unit_get_enable_mask(Unit *u) {
 
         mask = unit_get_members_mask(u);
         mask &= u->manager->cgroup_supported;
+        mask &= ~unit_get_ancestor_disable_mask(u);
 
         return mask;
 }
@@ -1551,7 +1623,8 @@ int unit_pick_cgroup_path(Unit *u) {
 static int unit_create_cgroup(
                 Unit *u,
                 CGroupMask target_mask,
-                CGroupMask enable_mask) {
+                CGroupMask enable_mask,
+                ManagerState state) {
 
         bool created;
         int r;
@@ -1619,6 +1692,10 @@ static int unit_create_cgroup(
                         log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path);
         }
 
+        /* Set attributes */
+        cgroup_context_apply(u, target_mask, state);
+        cgroup_xattr_apply(u);
+
         return 0;
 }
 
@@ -1760,26 +1837,6 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
         return r;
 }
 
-static void cgroup_xattr_apply(Unit *u) {
-        char ids[SD_ID128_STRING_MAX];
-        int r;
-
-        assert(u);
-
-        if (!MANAGER_IS_SYSTEM(u->manager))
-                return;
-
-        if (sd_id128_is_null(u->invocation_id))
-                return;
-
-        r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
-                         "trusted.invocation_id",
-                         sd_id128_to_string(u->invocation_id, ids), 32,
-                         0);
-        if (r < 0)
-                log_unit_debug_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,
@@ -1808,6 +1865,40 @@ static bool unit_has_mask_realized(
                 u->cgroup_invalidated_mask == 0;
 }
 
+static bool unit_has_mask_disables_realized(
+                Unit *u,
+                CGroupMask target_mask,
+                CGroupMask enable_mask) {
+
+        assert(u);
+
+        /* Returns true if all controllers which should be disabled are indeed disabled.
+         *
+         * Unlike unit_has_mask_realized, we don't care what was enabled, only that anything we want to remove is
+         * already removed. */
+
+        return !u->cgroup_realized ||
+                (FLAGS_SET(u->cgroup_realized_mask, target_mask & CGROUP_MASK_V1) &&
+                 FLAGS_SET(u->cgroup_enabled_mask, enable_mask & CGROUP_MASK_V2));
+}
+
+static bool unit_has_mask_enables_realized(
+                Unit *u,
+                CGroupMask target_mask,
+                CGroupMask enable_mask) {
+
+        assert(u);
+
+        /* Returns true if all controllers which should be enabled are indeed enabled.
+         *
+         * Unlike unit_has_mask_realized, we don't care about the controllers that are not present, only that anything
+         * we want to add is already added. */
+
+        return u->cgroup_realized &&
+                ((u->cgroup_realized_mask | target_mask) & CGROUP_MASK_V1) == (u->cgroup_realized_mask & CGROUP_MASK_V1) &&
+                ((u->cgroup_enabled_mask | enable_mask) & CGROUP_MASK_V2) == (u->cgroup_enabled_mask & CGROUP_MASK_V2);
+}
+
 void unit_add_to_cgroup_realize_queue(Unit *u) {
         assert(u);
 
@@ -1828,10 +1919,127 @@ static void unit_remove_from_cgroup_realize_queue(Unit *u) {
         u->in_cgroup_realize_queue = false;
 }
 
+/* Controllers can only be enabled breadth-first, from the root of the
+ * hierarchy downwards to the unit in question. */
+static int unit_realize_cgroup_now_enable(Unit *u, ManagerState state) {
+        CGroupMask target_mask, enable_mask, new_target_mask, new_enable_mask;
+        int r;
+
+        assert(u);
+
+        /* First go deal with this unit's parent, or we won't be able to enable
+         * any new controllers at this layer. */
+        if (UNIT_ISSET(u->slice)) {
+                r = unit_realize_cgroup_now_enable(UNIT_DEREF(u->slice), state);
+                if (r < 0)
+                        return r;
+        }
+
+        target_mask = unit_get_target_mask(u);
+        enable_mask = unit_get_enable_mask(u);
+
+        /* We can only enable in this direction, don't try to disable anything.
+         */
+        if (unit_has_mask_enables_realized(u, target_mask, enable_mask))
+                return 0;
+
+        new_target_mask = u->cgroup_realized_mask | target_mask;
+        new_enable_mask = u->cgroup_enabled_mask | enable_mask;
+
+        return unit_create_cgroup(u, new_target_mask, new_enable_mask, state);
+}
+
+/* Controllers can only be disabled depth-first, from the leaves of the
+ * hierarchy upwards to the unit in question. */
+static int unit_realize_cgroup_now_disable(Unit *u, ManagerState state) {
+        Iterator i;
+        Unit *m;
+        void *v;
+
+        assert(u);
+
+        if (u->type != UNIT_SLICE)
+                return 0;
+
+        HASHMAP_FOREACH_KEY(v, m, u->dependencies[UNIT_BEFORE], i) {
+                CGroupMask target_mask, enable_mask, new_target_mask, new_enable_mask;
+                int r;
+
+                if (UNIT_DEREF(m->slice) != u)
+                        continue;
+
+                /* The cgroup for this unit might not actually be fully
+                 * realised yet, in which case it isn't holding any controllers
+                 * open anyway. */
+                if (!m->cgroup_path)
+                        continue;
+
+                /* We must disable those below us first in order to release the
+                 * controller. */
+                if (m->type == UNIT_SLICE)
+                        (void) unit_realize_cgroup_now_disable(m, state);
+
+                target_mask = unit_get_target_mask(m);
+                enable_mask = unit_get_enable_mask(m);
+
+                /* We can only disable in this direction, don't try to enable
+                 * anything. */
+                if (unit_has_mask_disables_realized(m, target_mask, enable_mask))
+                        continue;
+
+                new_target_mask = m->cgroup_realized_mask & target_mask;
+                new_enable_mask = m->cgroup_enabled_mask & enable_mask;
+
+                r = unit_create_cgroup(m, new_target_mask, new_enable_mask, state);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 /* Check if necessary controllers and attributes for a unit are in place.
  *
- * If so, do nothing.
- * If not, create paths, move processes over, and set attributes.
+ * - If so, do nothing.
+ * - If not, create paths, move processes over, and set attributes.
+ *
+ * Controllers can only be *enabled* in a breadth-first way, and *disabled* in
+ * a depth-first way. As such the process looks like this:
+ *
+ * Suppose we have a cgroup hierarchy which looks like this:
+ *
+ *             root
+ *            /    \
+ *           /      \
+ *          /        \
+ *         a          b
+ *        / \        / \
+ *       /   \      /   \
+ *      c     d    e     f
+ *     / \   / \  / \   / \
+ *     h i   j k  l m   n o
+ *
+ * 1. We want to realise cgroup "d" now.
+ * 2. cgroup "a" has DisableControllers=cpu in the associated unit.
+ * 3. cgroup "k" just started requesting the memory controller.
+ *
+ * To make this work we must do the following in order:
+ *
+ * 1. Disable CPU controller in k, j
+ * 2. Disable CPU controller in d
+ * 3. Enable memory controller in root
+ * 4. Enable memory controller in a
+ * 5. Enable memory controller in d
+ * 6. Enable memory controller in k
+ *
+ * Notice that we need to touch j in one direction, but not the other. We also
+ * don't go beyond d when disabling -- it's up to "a" to get realized if it
+ * wants to disable further. The basic rules are therefore:
+ *
+ * - If you're disabling something, you need to realise all of the cgroups from
+ *   your recursive descendants to the root. This starts from the leaves.
+ * - If you're enabling something, you need to realise from the root cgroup
+ *   downwards, but you don't need to iterate your recursive descendants.
  *
  * Returns 0 on success and < 0 on failure. */
 static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
@@ -1848,22 +2056,23 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
         if (unit_has_mask_realized(u, target_mask, enable_mask))
                 return 0;
 
-        /* First, realize parents */
+        /* Disable controllers below us, if there are any */
+        r = unit_realize_cgroup_now_disable(u, state);
+        if (r < 0)
+                return r;
+
+        /* Enable controllers above us, if there are any */
         if (UNIT_ISSET(u->slice)) {
-                r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
+                r = unit_realize_cgroup_now_enable(UNIT_DEREF(u->slice), state);
                 if (r < 0)
                         return r;
         }
 
-        /* And then do the real work */
-        r = unit_create_cgroup(u, target_mask, enable_mask);
+        /* Now actually deal with the cgroup we were trying to realise and set attributes */
+        r = unit_create_cgroup(u, target_mask, enable_mask, state);
         if (r < 0)
                 return r;
 
-        /* Finally, apply the necessary attributes. */
-        cgroup_context_apply(u, target_mask, state);
-        cgroup_xattr_apply(u);
-
         /* Now, reset the invalidation mask */
         u->cgroup_invalidated_mask = 0;
         return 0;
index 828b6f07951ab77411f6a634275aab4f3dee4d62..6d094e9ecda9ef90ca859b0ea454c77ee086519f 100644 (file)
@@ -118,6 +118,8 @@ struct CGroupContext {
 
         bool delegate;
         CGroupMask delegate_controllers;
+
+        CGroupMask disable_controllers;
 };
 
 /* Used when querying IP accounting data */
@@ -151,6 +153,9 @@ CGroupMask unit_get_delegate_mask(Unit *u);
 CGroupMask unit_get_members_mask(Unit *u);
 CGroupMask unit_get_siblings_mask(Unit *u);
 CGroupMask unit_get_subtree_mask(Unit *u);
+CGroupMask unit_get_disable_mask(Unit *u);
+CGroupMask unit_get_ancestor_disable_mask(Unit *u);
+
 CGroupMask unit_get_target_mask(Unit *u);
 CGroupMask unit_get_enable_mask(Unit *u);
 
index a2f532076dcdf0798c24b10f98d154c3ff471e76..53890bcafbfe49317c1cd0191b1ba7c078d9342f 100644 (file)
@@ -17,7 +17,7 @@
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
 
-static int property_get_delegate_controllers(
+static int property_get_cgroup_mask(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
@@ -26,26 +26,22 @@ static int property_get_delegate_controllers(
                 void *userdata,
                 sd_bus_error *error) {
 
-        CGroupContext *c = userdata;
-        CGroupController cc;
+        CGroupMask *mask = userdata;
+        CGroupController ctrl;
         int r;
 
         assert(bus);
         assert(reply);
-        assert(c);
-
-        if (!c->delegate)
-                return sd_bus_message_append(reply, "as", 0);
 
         r = sd_bus_message_open_container(reply, 'a', "s");
         if (r < 0)
                 return r;
 
-        for (cc = 0; cc < _CGROUP_CONTROLLER_MAX; cc++) {
-                if ((c->delegate_controllers & CGROUP_CONTROLLER_TO_MASK(cc)) == 0)
+        for (ctrl = 0; ctrl < _CGROUP_CONTROLLER_MAX; ctrl++) {
+                if ((*mask & CGROUP_CONTROLLER_TO_MASK(ctrl)) == 0)
                         continue;
 
-                r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(cc));
+                r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(ctrl));
                 if (r < 0)
                         return r;
         }
@@ -53,6 +49,27 @@ static int property_get_delegate_controllers(
         return sd_bus_message_close_container(reply);
 }
 
+static int property_get_delegate_controllers(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        CGroupContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        if (!c->delegate)
+                return sd_bus_message_append(reply, "as", 0);
+
+        return property_get_cgroup_mask(bus, path, interface, property, reply, &c->delegate_controllers, error);
+}
+
 static int property_get_io_device_weight(
                 sd_bus *bus,
                 const char *path,
@@ -342,6 +359,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         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_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0),
         SD_BUS_VTABLE_END
 };
 
index 31f9099b98e872e8a9422df9f20f4f1cf510f378..11301e4b693679d91f73ed1d6c964030a2b65c12 100644 (file)
@@ -27,7 +27,7 @@
 #include "ioprio.h"
 #include "journal-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "namespace.h"
 #include "parse-util.h"
 #include "path-util.h"
index 20d890b36c37685201a28e3ba5e680ade9094101..d11e58b51ddd5cde5a0a23ed8f6842416984634f 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "alloc-util.h"
 #include "dbus-job.h"
+#include "dbus-unit.h"
 #include "dbus.h"
 #include "job.h"
 #include "log.h"
@@ -173,6 +174,9 @@ void bus_job_send_change_signal(Job *j) {
 
         assert(j);
 
+        /* Make sure that any change signal on the unit is reflected before we send out the change signal on the job */
+        bus_unit_send_pending_change_signal(j->unit, true);
+
         if (j->in_dbus_queue) {
                 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
                 j->in_dbus_queue = false;
@@ -185,6 +189,21 @@ void bus_job_send_change_signal(Job *j) {
         j->sent_dbus_new_signal = true;
 }
 
+void bus_job_send_pending_change_signal(Job *j, bool including_new) {
+        assert(j);
+
+        if (!j->in_dbus_queue)
+                return;
+
+        if (!j->sent_dbus_new_signal && !including_new)
+                return;
+
+        if (MANAGER_IS_RELOADING(j->unit->manager))
+                return;
+
+        bus_job_send_change_signal(j);
+}
+
 static int send_removed_signal(sd_bus *bus, void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *p = NULL;
@@ -222,6 +241,9 @@ void bus_job_send_removed_signal(Job *j) {
         if (!j->sent_dbus_new_signal)
                 bus_job_send_change_signal(j);
 
+        /* Make sure that any change signal on the unit is reflected before we send out the change signal on the job */
+        bus_unit_send_pending_change_signal(j->unit, true);
+
         r = bus_foreach_bus(j->manager, j->bus_track, send_removed_signal, j);
         if (r < 0)
                 log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id);
index 3cc60f22ee069199bb545b6b8767c477389929f0..c9f6fc718719861cd6e8fae308843fcb17fc1003 100644 (file)
@@ -12,6 +12,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *erro
 int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
 void bus_job_send_change_signal(Job *j);
+void bus_job_send_pending_change_signal(Job *j, bool including_new);
 void bus_job_send_removed_signal(Job *j);
 
 int bus_job_coldplug_bus_track(Job *j);
index 3819653908fd850558f9c4cc21d86b5d2a5e0252..37cf9d204c726a66c6e0216398c21858c8065a62 100644 (file)
@@ -8,10 +8,10 @@
 #include "dbus-socket.h"
 #include "dbus-util.h"
 #include "fd-util.h"
+#include "ip-protocol-list.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "socket.h"
-#include "socket-protocol-list.h"
 #include "socket-util.h"
 #include "string-util.h"
 #include "unit.h"
@@ -138,14 +138,14 @@ static inline bool check_size_t_truncation(uint64_t t) {
         return (size_t) t == t;
 }
 
-static inline const char* supported_socket_protocol_to_string(int32_t i) {
+static inline const char* socket_protocol_to_string(int32_t i) {
         if (i == IPPROTO_IP)
                 return "";
 
         if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
                 return NULL;
 
-        return socket_protocol_to_name(i);
+        return ip_protocol_to_name(i);
 }
 
 static BUS_DEFINE_SET_TRANSIENT(int, "i", int32_t, int, "%" PRIi32);
@@ -155,7 +155,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(bind_ipv6_only, SocketAddressBindIPv6Only,
 static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(fdname, fdname_is_valid);
 static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(ifname, ifname_valid);
 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(ip_tos, "i", int32_t, int, "%" PRIi32, ip_tos_to_string_alloc);
-static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, supported_socket_protocol_to_string);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, socket_protocol_to_string);
 
 static int bus_socket_set_transient_property(
                 Socket *s,
index 6d9b559d2c7d522ff63f561edb41b66f9fc007b6..968166ee60409dca2970490cbfa2bbfd1c85af3e 100644 (file)
@@ -662,8 +662,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
-        SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
+        SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+        SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -675,8 +675,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("SuccessAction", "s", property_get_emergency_action, offsetof(Unit, success_action), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SuccessActionExitStatus", "i", bus_property_get_int, offsetof(Unit, success_action_exit_status), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0),
-        SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), 0),
+        SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
 
         SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1202,6 +1202,27 @@ void bus_unit_send_change_signal(Unit *u) {
         u->sent_dbus_new_signal = true;
 }
 
+void bus_unit_send_pending_change_signal(Unit *u, bool including_new) {
+
+        /* Sends out any pending change signals, but only if they really are pending. This call is used when we are
+         * about to change state in order to force out a PropertiesChanged signal beforehand if there was one pending
+         * so that clients can follow the full state transition */
+
+        if (!u->in_dbus_queue) /* If not enqueued, don't bother */
+                return;
+
+        if (!u->sent_dbus_new_signal && !including_new) /* If the unit was never announced, don't bother, it's fine if
+                                                         * the unit appears in the new state right-away (except if the
+                                                         * caller explicitly asked us to send it anyway) */
+                return;
+
+        if (MANAGER_IS_RELOADING(u->manager)) /* Don't generate unnecessary PropertiesChanged signals for the same unit
+                                               * when we are reloading. */
+                return;
+
+        bus_unit_send_change_signal(u);
+}
+
 static int send_removed_signal(sd_bus *bus, void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *p = NULL;
@@ -1300,6 +1321,9 @@ int bus_unit_queue_job(
         if (!path)
                 return -ENOMEM;
 
+        /* Before we send the method reply, force out the announcement JobNew for this job */
+        bus_job_send_pending_change_signal(j, true);
+
         return sd_bus_reply_method_return(message, "o", path);
 }
 
index 68eb621836b1a77d79e8f46e4d0e2c4f1c44aceb..345345e3ebadea254c0ab0bd1697b40b15fea79c 100644 (file)
@@ -11,6 +11,7 @@ extern const sd_bus_vtable bus_unit_vtable[];
 extern const sd_bus_vtable bus_unit_cgroup_vtable[];
 
 void bus_unit_send_change_signal(Unit *u);
+void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
 void bus_unit_send_removed_signal(Unit *u);
 
 int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
index 8b6126c4cfe8e95e9b0e4fb06421d6fc8e177e17..5acd9b7a7036de7652f2255de69e92f6f3eb4109 100644 (file)
@@ -6,6 +6,7 @@
 #include "alloc-util.h"
 #include "bus-error.h"
 #include "dbus-device.h"
+#include "dbus-unit.h"
 #include "device-private.h"
 #include "device-util.h"
 #include "device.h"
@@ -115,6 +116,9 @@ static void device_set_state(Device *d, DeviceState state) {
         DeviceState old_state;
         assert(d);
 
+        if (d->state != state)
+                bus_unit_send_pending_change_signal(UNIT(d), false);
+
         old_state = d->state;
         d->state = state;
 
index 33ba2eca56e58349a889a4ced2a8935b0855443f..e966f9cfe85ee48717f3e02ea62b98d4e0aa1dc2 100644 (file)
 #include "chown-recursive.h"
 #include "cpu-set-util.h"
 #include "def.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "errno-list.h"
 #include "execute.h"
 #include "exit-status.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "glob-util.h"
@@ -76,7 +76,6 @@
 #if HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
-#include "securebits.h"
 #include "securebits-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
index 16124cf28c41af5dcc5ed127440cd450ccdcc1ae..fb8c752efaa1af9815a6b5f6a232aa0eecf90e82 100644 (file)
@@ -16,7 +16,7 @@ typedef struct Manager Manager;
 #include "cgroup-util.h"
 #include "fdset.h"
 #include "list.h"
-#include "missing.h"
+#include "missing_resource.h"
 #include "namespace.h"
 #include "nsflags.h"
 
index 2a630356bfa5738bf6994b70c5ac693180c88ef8..af5070b8cf9acb3c3802b4fe0bdf0ef5e4be9ab5 100644 (file)
@@ -236,6 +236,9 @@ Job* job_install(Job *j) {
 
         job_add_to_gc_queue(j);
 
+        job_add_to_dbus_queue(j); /* announce this job to clients */
+        unit_add_to_dbus_queue(j->unit); /* The Job property of the unit has changed now */
+
         return j;
 }
 
@@ -306,7 +309,7 @@ void job_dependency_free(JobDependency *l) {
         free(l);
 }
 
-void job_dump(Job *j, FILE*f, const char *prefix) {
+void job_dump(Job *j, FILE *f, const char *prefix) {
         assert(j);
         assert(f);
 
index db14a1732c625993d3d263b6f2934e446b57af18..5f9c14012ff92b22f54f5d387c8ade4ace422a74 100644 (file)
@@ -166,7 +166,7 @@ void job_free(Job *job);
 Job* job_install(Job *j);
 int job_install_deserialized(Job *j);
 void job_uninstall(Job *j);
-void job_dump(Job *j, FILE*f, const char *prefix);
+void job_dump(Job *j, FILE *f, const char *prefix);
 int job_serialize(Job *j, FILE *f);
 int job_deserialize(Job *j, FILE *f);
 int job_coldplug(Job *j);
index 97a707c1447e3e486f0e853212d1f13343335fc3..cdbc67f885d2f4c689d290d3bcfbb6b309de618a 100644 (file)
@@ -192,6 +192,7 @@ $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_delegate,              0,                             offsetof($1, cgroup_context)
+$1.DisableControllers,           config_parse_disable_controllers,   0,                             offsetof($1, cgroup_context)
 $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)
index 067d36dad51b72d123ab1743bb1cd450c9c11470..36e874de2948cea6e7c5b342c2a75dadd91d690d 100644 (file)
 #include "hexdecoct.h"
 #include "io-util.h"
 #include "ioprio.h"
+#include "ip-protocol-list.h"
 #include "journal-util.h"
 #include "load-fragment.h"
 #include "log.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #if HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
-#include "securebits.h"
 #include "securebits-util.h"
 #include "signal-util.h"
-#include "socket-protocol-list.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "user-util.h"
 #include "web-util.h"
 
-static int supported_socket_protocol_from_string(const char *s) {
+static int parse_socket_protocol(const char *s) {
         int r;
 
-        if (isempty(s))
-                return IPPROTO_IP;
-
-        r = socket_protocol_from_name(s);
+        r = parse_ip_protocol(s);
         if (r < 0)
                 return r;
         if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP))
@@ -72,7 +68,7 @@ static int supported_socket_protocol_from_string(const char *s) {
         return r;
 }
 
-DEFINE_CONFIG_PARSE(config_parse_socket_protocol, supported_socket_protocol_from_string, "Failed to parse socket protocol");
+DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol, "Failed to parse socket protocol");
 DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
@@ -4326,6 +4322,41 @@ int config_parse_exit_status(
         return 0;
 }
 
+int config_parse_disable_controllers(
+                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 r;
+        CGroupContext *c = data;
+        CGroupMask disabled_mask;
+
+        /* 1. If empty, make all controllers eligible for use again.
+         * 2. If non-empty, merge all listed controllers, space separated. */
+
+        if (isempty(rvalue)) {
+                c->disable_controllers = 0;
+                return 0;
+        }
+
+        r = cg_mask_from_string(rvalue, &disabled_mask);
+        if (r < 0 || disabled_mask <= 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid cgroup string: %s, ignoring", rvalue);
+                return 0;
+        }
+
+        c->disable_controllers |= disabled_mask;
+
+        return 0;
+}
+
 #define FOLLOW_MAX 8
 
 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
index 71d94a77629becc2d25373989d303cc1978cbc99..e0d3b4ec3bddcc39ac5ca1051ef3311e7aa164fb 100644 (file)
@@ -105,6 +105,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields);
 CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_pid_file);
 CONFIG_PARSER_PROTOTYPE(config_parse_exit_status);
+CONFIG_PARSER_PROTOTYPE(config_parse_disable_controllers);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
index fff3a798c41104b7f3f031724ede695ac1b698a6..584fb220a107ab6cb4a81e1dd7e20419798cbb78 100644 (file)
@@ -4,8 +4,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "env-file.h"
 #include "env-util.h"
-#include "fileio.h"
 #include "locale-setup.h"
 #include "locale-util.h"
 #include "proc-cmdline.h"
index 4dfdc475baf8ea930d5ca25e77e50d25c4586952..aae548064e5035fb7c9f9d2898d68e3528073903 100644 (file)
@@ -15,7 +15,7 @@
 #include "machine-id-setup.h"
 #include "macro.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "stat-util.h"
index 6d03b066847d5c45c5c52b1e64f7fc2a28a26f46..839dc062ff780700c9213beec517468c6ed66bcb 100644 (file)
@@ -236,6 +236,7 @@ _noreturn_ static void crash(int sig) {
                 else if (pid == 0) {
                         (void) setsid();
                         (void) make_console_stdio();
+                        (void) rlimit_nofile_safe();
                         (void) execle("/bin/sh", "/bin/sh", NULL, environ);
 
                         log_emergency_errno(errno, "execle() failed: %m");
@@ -1733,6 +1734,7 @@ static void do_reexecute(
         /* Reenable any blocked signals, especially important if we switch from initial ramdisk to init=... */
         (void) reset_all_signal_handlers();
         (void) reset_signal_mask();
+        (void) rlimit_nofile_safe();
 
         if (switch_root_init) {
                 args[0] = switch_root_init;
index e15d94d98a2b226c977f8d270658bdd96efc77ad..a686b64e6680f950f027f388166aa740d8b72bd5 100644 (file)
@@ -20,7 +20,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-setup.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "smack-util.h"
@@ -460,20 +460,9 @@ int mount_setup(bool loaded_policy) {
         (void) mkdir_label("/run/systemd", 0755);
         (void) mkdir_label("/run/systemd/system", 0755);
 
-        /* Set up inaccessible (and empty) file nodes of all types */
-        (void) mkdir_label("/run/systemd/inaccessible", 0000);
-        (void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
-        (void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
-        (void) mkfifo("/run/systemd/inaccessible/fifo", 0000);
-        (void) mknod("/run/systemd/inaccessible/sock", S_IFSOCK | 0000, 0);
-
-        /* The following two are likely to fail if we lack the privs for it (for example in an userns environment, if
-         * CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0 device nodes to be
-         * created). But that's entirely fine. Consumers of these files should carry fallback to use a different node
-         * then, for example /run/systemd/inaccessible/sock, which is close enough in behaviour and semantics for most
-         * uses. */
-        (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
-        (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0));
+        /* Also create /run/systemd/inaccessible nodes, so that we always have something to mount inaccessible nodes
+         * from. */
+        (void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
 
         return 0;
 }
index 8c19150112c72ea01aa4063e1b9c534ecdd41653..ead9bc1f441564993b20c7e78c22327a904a71e4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "alloc-util.h"
 #include "dbus-mount.h"
+#include "dbus-unit.h"
 #include "device.h"
 #include "escape.h"
 #include "exit-status.h"
@@ -20,8 +21,8 @@
 #include "manager.h"
 #include "mkdir.h"
 #include "mount-setup.h"
-#include "mount-util.h"
 #include "mount.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -67,22 +68,18 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
                       MOUNT_UNMOUNTING_SIGKILL);
 }
 
-static bool mount_needs_network(const char *options, const char *fstype) {
-        if (fstab_test_option(options, "_netdev\0"))
+static bool mount_is_network(const MountParameters *p) {
+        assert(p);
+
+        if (fstab_test_option(p->options, "_netdev\0"))
                 return true;
 
-        if (fstype && fstype_is_network(fstype))
+        if (p->fstype && fstype_is_network(p->fstype))
                 return true;
 
         return false;
 }
 
-static bool mount_is_network(const MountParameters *p) {
-        assert(p);
-
-        return mount_needs_network(p->options, p->fstype);
-}
-
 static bool mount_is_loop(const MountParameters *p) {
         assert(p);
 
@@ -128,11 +125,11 @@ static bool mount_is_bound_to_device(const Mount *m) {
         return fstab_test_option(p->options, "x-systemd.device-bound\0");
 }
 
-static bool needs_quota(const MountParameters *p) {
+static bool mount_needs_quota(const MountParameters *p) {
         assert(p);
 
-        /* Quotas are not enabled on network filesystems,
-         * but we want them, for example, on storage connected via iscsi */
+        /* Quotas are not enabled on network filesystems, but we want them, for example, on storage connected via
+         * iscsi. We hence don't use mount_is_network() here, as that would also return true for _netdev devices. */
         if (p->fstype && fstype_is_network(p->fstype))
                 return false;
 
@@ -210,11 +207,9 @@ static void mount_unwatch_control_pid(Mount *m) {
 static void mount_parameters_done(MountParameters *p) {
         assert(p);
 
-        free(p->what);
-        free(p->options);
-        free(p->fstype);
-
-        p->what = p->options = p->fstype = NULL;
+        p->what = mfree(p->what);
+        p->options = mfree(p->options);
+        p->fstype = mfree(p->fstype);
 }
 
 static void mount_done(Unit *u) {
@@ -317,7 +312,7 @@ static int mount_add_mount_dependencies(Mount *m) {
 }
 
 static int mount_add_device_dependencies(Mount *m) {
-        bool device_wants_mount = false;
+        bool device_wants_mount;
         UnitDependencyMask mask;
         MountParameters *p;
         UnitDependency dep;
@@ -347,8 +342,8 @@ static int mount_add_device_dependencies(Mount *m) {
         if (path_equal(m->where, "/"))
                 return 0;
 
-        if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
-                device_wants_mount = true;
+        device_wants_mount =
+                mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager);
 
         /* Mount units from /proc/self/mountinfo are not bound to devices
          * by default since they're subject to races when devices are
@@ -380,7 +375,7 @@ static int mount_add_quota_dependencies(Mount *m) {
         if (!p)
                 return 0;
 
-        if (!needs_quota(p))
+        if (!mount_needs_quota(p))
                 return 0;
 
         mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
@@ -428,10 +423,10 @@ static bool mount_is_extrinsic(Mount *m) {
 }
 
 static int mount_add_default_dependencies(Mount *m) {
+        const char *after, *before;
         UnitDependencyMask mask;
-        int r;
         MountParameters *p;
-        const char *after;
+        int r;
 
         assert(m);
 
@@ -473,8 +468,15 @@ static int mount_add_default_dependencies(Mount *m) {
                         return r;
 
                 after = SPECIAL_REMOTE_FS_PRE_TARGET;
-        } else
+                before = SPECIAL_REMOTE_FS_TARGET;
+        } else {
                 after = SPECIAL_LOCAL_FS_PRE_TARGET;
+                before = SPECIAL_LOCAL_FS_TARGET;
+        }
+
+        r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
+        if (r < 0)
+                return r;
 
         r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
         if (r < 0)
@@ -541,6 +543,10 @@ static int mount_add_extras(Mount *m) {
 
         assert(m);
 
+        /* Note: this call might be called after we already have been loaded once (and even when it has already been
+         * activated), in case data from /proc/self/mountinfo has changed. This means all code here needs to be ready
+         * to run with an already set up unit. */
+
         if (u->fragment_path)
                 m->from_fragment = true;
 
@@ -610,28 +616,33 @@ static int mount_load_root_mount(Unit *u) {
 
 static int mount_load(Unit *u) {
         Mount *m = MOUNT(u);
-        int r;
+        int r, q, w;
 
         assert(u);
         assert(u->load_state == UNIT_STUB);
 
         r = mount_load_root_mount(u);
-        if (r < 0)
-                return r;
 
         if (m->from_proc_self_mountinfo || u->perpetual)
-                r = unit_load_fragment_and_dropin_optional(u);
+                q = unit_load_fragment_and_dropin_optional(u);
         else
-                r = unit_load_fragment_and_dropin(u);
+                q = unit_load_fragment_and_dropin(u);
+
+        /* Add in some extras. Note we do this in all cases (even if we failed to load the unit) when announced by the
+         * kernel, because we need some things to be set up no matter what when the kernel establishes a mount and thus
+         * we need to update the state in our unit to track it. After all, consider that we don't allow changing the
+         * 'slice' field for a unit once it is active. */
+        if (u->load_state == UNIT_LOADED || m->from_proc_self_mountinfo || u->perpetual)
+                w = mount_add_extras(m);
+        else
+                w = 0;
+
         if (r < 0)
                 return r;
-
-        /* This is a new unit? Then let's add in some extras */
-        if (u->load_state == UNIT_LOADED) {
-                r = mount_add_extras(m);
-                if (r < 0)
-                        return r;
-        }
+        if (q < 0)
+                return q;
+        if (w < 0)
+                return w;
 
         return mount_verify(m);
 }
@@ -640,6 +651,9 @@ static void mount_set_state(Mount *m, MountState state) {
         MountState old_state;
         assert(m);
 
+        if (m->state != state)
+                bus_unit_send_pending_change_signal(UNIT(m), false);
+
         old_state = m->state;
         m->state = state;
 
@@ -940,7 +954,6 @@ static void mount_enter_mounting(Mount *m) {
         (void) mkdir_p_label(m->where, m->directory_mode);
 
         unit_warn_if_dir_nonempty(UNIT(m), m->where);
-
         unit_warn_leftover_processes(UNIT(m));
 
         m->control_command_id = MOUNT_EXEC_MOUNT;
@@ -1044,6 +1057,17 @@ fail:
         mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
 }
 
+static void mount_cycle_clear(Mount *m) {
+        assert(m);
+
+        /* Clear all state we shall forget for this new cycle */
+
+        m->result = MOUNT_SUCCESS;
+        m->reload_result = MOUNT_SUCCESS;
+        exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
+        UNIT(m)->reset_accounting = true;
+}
+
 static int mount_start(Unit *u) {
         Mount *m = MOUNT(u);
         int r;
@@ -1074,13 +1098,9 @@ static int mount_start(Unit *u) {
         if (r < 0)
                 return r;
 
-        m->result = MOUNT_SUCCESS;
-        m->reload_result = MOUNT_SUCCESS;
-        exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
-
-        u->reset_accounting = true;
-
+        mount_cycle_clear(m);
         mount_enter_mounting(m);
+
         return 1;
 }
 
@@ -1144,6 +1164,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
         (void) serialize_item(f, "state", mount_state_to_string(m->state));
         (void) serialize_item(f, "result", mount_result_to_string(m->result));
         (void) serialize_item(f, "reload-result", mount_result_to_string(m->reload_result));
+        (void) serialize_item_format(f, "n-retry-umount", "%u", m->n_retry_umount);
 
         if (m->control_pid > 0)
                 (void) serialize_item_format(f, "control-pid", PID_FMT, m->control_pid);
@@ -1156,6 +1177,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
 
 static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
         Mount *m = MOUNT(u);
+        int r;
 
         assert(u);
         assert(key);
@@ -1169,6 +1191,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
                         log_unit_debug(u, "Failed to parse state value: %s", value);
                 else
                         m->deserialized_state = state;
+
         } else if (streq(key, "result")) {
                 MountResult f;
 
@@ -1187,13 +1210,17 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
                 else if (f != MOUNT_SUCCESS)
                         m->reload_result = f;
 
+        } else if (streq(key, "n-retry-umount")) {
+
+                r = safe_atou(value, &m->n_retry_umount);
+                if (r < 0)
+                        log_unit_debug(u, "Failed to parse n-retry-umount value: %s", value);
+
         } else if (streq(key, "control-pid")) {
-                pid_t pid;
 
-                if (parse_pid(value, &pid) < 0)
+                if (parse_pid(value, &m->control_pid) < 0)
                         log_unit_debug(u, "Failed to parse control-pid value: %s", value);
-                else
-                        m->control_pid = pid;
+
         } else if (streq(key, "control-command")) {
                 MountExecCommand id;
 
@@ -1401,59 +1428,77 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
         return 0;
 }
 
-typedef struct {
-        bool is_mounted;
-        bool just_mounted;
-        bool just_changed;
-} MountSetupFlags;
+static int update_parameters_proc_self_mount_info(
+                Mount *m,
+                const char *what,
+                const char *options,
+                const char *fstype) {
+
+        MountParameters *p;
+        int r, q, w;
+
+        p = &m->parameters_proc_self_mountinfo;
+
+        r = free_and_strdup(&p->what, what);
+        if (r < 0)
+                return r;
+
+        q = free_and_strdup(&p->options, options);
+        if (q < 0)
+                return q;
+
+        w = free_and_strdup(&p->fstype, fstype);
+        if (w < 0)
+                return w;
+
+        return r > 0 || q > 0 || w > 0;
+}
 
 static int mount_setup_new_unit(
-                Unit *u,
+                Manager *m,
+                const char *name,
                 const char *what,
                 const char *where,
                 const char *options,
                 const char *fstype,
-                MountSetupFlags *flags) {
-
-        MountParameters *p;
+                MountProcFlags *ret_flags,
+                Unit **ret) {
 
-        assert(u);
-        assert(flags);
+        _cleanup_(unit_freep) Unit *u = NULL;
+        int r;
 
-        u->source_path = strdup("/proc/self/mountinfo");
-        MOUNT(u)->where = strdup(where);
-        if (!u->source_path || !MOUNT(u)->where)
-                return -ENOMEM;
+        assert(m);
+        assert(name);
+        assert(ret_flags);
+        assert(ret);
 
-        /* Make sure to initialize those fields before mount_is_extrinsic(). */
-        MOUNT(u)->from_proc_self_mountinfo = true;
-        p = &MOUNT(u)->parameters_proc_self_mountinfo;
+        r = unit_new_for_name(m, sizeof(Mount), name, &u);
+        if (r < 0)
+                return r;
 
-        p->what = strdup(what);
-        p->options = strdup(options);
-        p->fstype = strdup(fstype);
-        if (!p->what || !p->options || !p->fstype)
-                return -ENOMEM;
+        r = free_and_strdup(&u->source_path, "/proc/self/mountinfo");
+        if (r < 0)
+                return r;
 
-        if (!mount_is_extrinsic(MOUNT(u))) {
-                const char *target;
-                int r;
+        r = free_and_strdup(&MOUNT(u)->where, where);
+        if (r < 0)
+                return r;
 
-                target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
-                r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
-                if (r < 0)
-                        return r;
+        r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype);
+        if (r < 0)
+                return r;
 
-                r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
-                if (r < 0)
-                        return r;
-        }
+        /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load
+         * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps
+         * to.*/
+        MOUNT(u)->from_proc_self_mountinfo = true;
 
+        /* We have only allocated the stub now, let's enqueue this unit for loading now, so that everything else is
+         * loaded in now. */
         unit_add_to_load_queue(u);
-        flags->is_mounted = true;
-        flags->just_mounted = true;
-        flags->just_changed = true;
 
+        *ret_flags = MOUNT_PROC_IS_MOUNTED | MOUNT_PROC_JUST_MOUNTED | MOUNT_PROC_JUST_CHANGED;
+        *ret = TAKE_PTR(u);
         return 0;
 }
 
@@ -1463,11 +1508,10 @@ static int mount_setup_existing_unit(
                 const char *where,
                 const char *options,
                 const char *fstype,
-                MountSetupFlags *flags) {
+                MountProcFlags *ret_flags) {
 
-        MountParameters *p;
-        bool load_extras = false;
-        int r1, r2, r3;
+        MountProcFlags flags = MOUNT_PROC_IS_MOUNTED;
+        int r;
 
         assert(u);
         assert(flags);
@@ -1478,49 +1522,38 @@ static int mount_setup_existing_unit(
                         return -ENOMEM;
         }
 
-        /* Make sure to initialize those fields before mount_is_extrinsic(). */
-        p = &MOUNT(u)->parameters_proc_self_mountinfo;
-
-        r1 = free_and_strdup(&p->what, what);
-        r2 = free_and_strdup(&p->options, options);
-        r3 = free_and_strdup(&p->fstype, fstype);
-        if (r1 < 0 || r2 < 0 || r3 < 0)
-                return -ENOMEM;
-
-        flags->just_changed = r1 > 0 || r2 > 0 || r3 > 0;
-        flags->is_mounted = true;
-        flags->just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted;
-
-        MOUNT(u)->from_proc_self_mountinfo = true;
+        r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype);
+        if (r < 0)
+                return r;
+        if (r > 0)
+                flags |= MOUNT_PROC_JUST_CHANGED;
 
-        if (!mount_is_extrinsic(MOUNT(u)) && mount_is_network(p)) {
-                /* _netdev option may have shown up late, or on a
-                 * remount. Add remote-fs dependencies, even though
-                 * local-fs ones may already be there.
-                 *
-                 * Note: due to a current limitation (we don't track
-                 * in the dependency "Set*" objects who created a
-                 * dependency), we can only add deps, never lose them,
-                 * until the next full daemon-reload. */
-                unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
-                load_extras = true;
+        if (!MOUNT(u)->from_proc_self_mountinfo) {
+                flags |= MOUNT_PROC_JUST_MOUNTED;
+                MOUNT(u)->from_proc_self_mountinfo = true;
         }
 
-        if (u->load_state == UNIT_NOT_FOUND) {
+        if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+                /* The unit was previously not found or otherwise not loaded. Now that the unit shows up in
+                 * /proc/self/mountinfo we should reconsider it this, hence set it to UNIT_LOADED. */
                 u->load_state = UNIT_LOADED;
                 u->load_error = 0;
 
-                /* Load in the extras later on, after we
-                 * finished initialization of the unit */
-
-                /* FIXME: since we're going to load the unit later on, why setting load_extras=true ? */
-                load_extras = true;
-                flags->just_changed = true;
+                flags |= MOUNT_PROC_JUST_CHANGED;
         }
 
-        if (load_extras)
-                return mount_add_extras(MOUNT(u));
+        if (FLAGS_SET(flags, MOUNT_PROC_JUST_CHANGED)) {
+                /* If things changed, then make sure that all deps are regenerated. Let's
+                 * first remove all automatic deps, and then add in the new ones. */
 
+                unit_remove_dependencies(u, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
+
+                r = mount_add_extras(MOUNT(u));
+                if (r < 0)
+                        return r;
+        }
+
+        *ret_flags = flags;
         return 0;
 }
 
@@ -1533,7 +1566,7 @@ static int mount_setup_unit(
                 bool set_flags) {
 
         _cleanup_free_ char *e = NULL;
-        MountSetupFlags flags;
+        MountProcFlags flags;
         Unit *u;
         int r;
 
@@ -1557,44 +1590,32 @@ static int mount_setup_unit(
 
         r = unit_name_from_path(where, ".mount", &e);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to generate unit name from path '%s': %m", where);
 
         u = manager_get_unit(m, e);
-        if (!u) {
-                /* First time we see this mount point meaning that it's
-                 * not been initiated by a mount unit but rather by the
-                 * sysadmin having called mount(8) directly. */
-                r = unit_new_for_name(m, sizeof(Mount), e, &u);
-                if (r < 0)
-                        goto fail;
-
-                r = mount_setup_new_unit(u, what, where, options, fstype, &flags);
-                if (r < 0)
-                        unit_free(u);
-        } else
+        if (u)
                 r = mount_setup_existing_unit(u, what, where, options, fstype, &flags);
-
+        else
+                /* First time we see this mount point meaning that it's not been initiated by a mount unit but rather
+                 * by the sysadmin having called mount(8) directly. */
+                r = mount_setup_new_unit(m, e, what, where, options, fstype, &flags, &u);
         if (r < 0)
-                goto fail;
-
-        if (set_flags) {
-                MOUNT(u)->is_mounted = flags.is_mounted;
-                MOUNT(u)->just_mounted = flags.just_mounted;
-                MOUNT(u)->just_changed = flags.just_changed;
-        }
+                return log_warning_errno(r, "Failed to set up mount unit: %m");
 
-        if (flags.just_changed)
+        /* If the mount changed properties or state, let's notify our clients */
+        if (flags & (MOUNT_PROC_JUST_CHANGED|MOUNT_PROC_JUST_MOUNTED))
                 unit_add_to_dbus_queue(u);
 
+        if (set_flags)
+                MOUNT(u)->proc_flags = flags;
+
         return 0;
-fail:
-        return log_warning_errno(r, "Failed to set up mount unit: %m");
 }
 
 static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
         _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
         _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
-        int r = 0;
+        int r;
 
         assert(m);
 
@@ -1607,7 +1628,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
         if (r < 0)
                 return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
 
-        r = 0;
         for (;;) {
                 struct libmnt_fs *fs;
                 const char *device, *path, *options, *fstype;
@@ -1636,12 +1656,10 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
 
                 device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
 
-                k = mount_setup_unit(m, d, p, options, fstype, set_flags);
-                if (r == 0 && k < 0)
-                        r = k;
+                (void) mount_setup_unit(m, d, p, options, fstype, set_flags);
         }
 
-        return r;
+        return 0;
 }
 
 static void mount_shutdown(Manager *m) {
@@ -1699,7 +1717,7 @@ static void mount_enumerate_perpetual(Manager *m) {
 static bool mount_is_mounted(Mount *m) {
         assert(m);
 
-        return UNIT(m)->perpetual || m->is_mounted;
+        return UNIT(m)->perpetual || FLAGS_SET(m->proc_flags, MOUNT_PROC_IS_MOUNTED);
 }
 
 static void mount_enumerate(Manager *m) {
@@ -1763,7 +1781,7 @@ fail:
 }
 
 static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
-        _cleanup_set_free_ Set *around = NULL, *gone = NULL;
+        _cleanup_set_free_free_ Set *around = NULL, *gone = NULL;
         Manager *m = userdata;
         const char *what;
         Iterator i;
@@ -1799,11 +1817,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
         r = mount_load_proc_self_mountinfo(m, true);
         if (r < 0) {
                 /* Reset flags, just in case, for later calls */
-                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
-                        Mount *mount = MOUNT(u);
-
-                        mount->is_mounted = mount->just_mounted = mount->just_changed = false;
-                }
+                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT])
+                        MOUNT(u)->proc_flags = 0;
 
                 return 0;
         }
@@ -1824,7 +1839,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
 
                                 /* Remember that this device might just have disappeared */
                                 if (set_ensure_allocated(&gone, &path_hash_ops) < 0 ||
-                                    set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0)
+                                    set_put_strdup(gone, mount->parameters_proc_self_mountinfo.what) < 0)
                                         log_oom(); /* we don't care too much about OOM here... */
                         }
 
@@ -1833,10 +1848,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                         switch (mount->state) {
 
                         case MOUNT_MOUNTED:
-                                /* This has just been unmounted by
-                                 * somebody else, follow the state
-                                 * change. */
-                                mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */
+                                /* This has just been unmounted by somebody else, follow the state change. */
                                 mount_enter_dead(mount, MOUNT_SUCCESS);
                                 break;
 
@@ -1844,7 +1856,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                                 break;
                         }
 
-                } else if (mount->just_mounted || mount->just_changed) {
+                } else if (mount->proc_flags & (MOUNT_PROC_JUST_MOUNTED|MOUNT_PROC_JUST_CHANGED)) {
 
                         /* A mount point was added or changed */
 
@@ -1855,7 +1867,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
 
                                 /* This has just been mounted by somebody else, follow the state change, but let's
                                  * generate a new invocation ID for this implicitly and automatically. */
-                                (void) unit_acquire_invocation_id(UNIT(mount));
+                                (void) unit_acquire_invocation_id(u);
+                                mount_cycle_clear(mount);
                                 mount_enter_mounted(mount, MOUNT_SUCCESS);
                                 break;
 
@@ -1877,14 +1890,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                 if (mount_is_mounted(mount) &&
                     mount->from_proc_self_mountinfo &&
                     mount->parameters_proc_self_mountinfo.what) {
+                        /* Track devices currently used */
 
                         if (set_ensure_allocated(&around, &path_hash_ops) < 0 ||
-                            set_put(around, mount->parameters_proc_self_mountinfo.what) < 0)
+                            set_put_strdup(around, mount->parameters_proc_self_mountinfo.what) < 0)
                                 log_oom();
                 }
 
                 /* Reset the flags for later calls */
-                mount->is_mounted = mount->just_mounted = mount->just_changed = false;
+                mount->proc_flags = 0;
         }
 
         SET_FOREACH(what, gone, i) {
index 67ab8ecf93a3ddeb1eb9c6c03bc85ece8e4a1efe..2e59f1fe04dd28f04c3146d7ba08de3b8db6f359 100644 (file)
@@ -34,6 +34,13 @@ typedef struct MountParameters {
         char *fstype;
 } MountParameters;
 
+/* Used while looking for mount points that vanished or got added from/to /proc/self/mountinfo */
+typedef enum MountProcFlags {
+        MOUNT_PROC_IS_MOUNTED   = 1 << 0,
+        MOUNT_PROC_JUST_MOUNTED = 1 << 1,
+        MOUNT_PROC_JUST_CHANGED = 1 << 2,
+} MountProcFlags;
+
 struct Mount {
         Unit meta;
 
@@ -45,11 +52,7 @@ struct Mount {
         bool from_proc_self_mountinfo:1;
         bool from_fragment:1;
 
-        /* Used while looking for mount points that vanished or got
-         * added from/to /proc/self/mountinfo */
-        bool is_mounted:1;
-        bool just_mounted:1;
-        bool just_changed:1;
+        MountProcFlags proc_flags;
 
         bool sloppy_options;
 
index 01516072a05844054be5c779bb22565e08dd80fe..c2ca3e0334c5631ae0a3d0090921afc292e957b5 100644 (file)
@@ -20,6 +20,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "namespace.h"
 #include "path-util.h"
 #include "selinux-util.h"
index 01019b0cf77f9e7027ab4d4e9ba87baa45598ed9..831e49df29f2623b0f9e0a49ffaeae66fcf198a8 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "dbus-path.h"
+#include "dbus-unit.h"
 #include "fd-util.h"
 #include "fs-util.h"
 #include "glob-util.h"
@@ -410,6 +411,9 @@ static void path_set_state(Path *p, PathState state) {
         PathState old_state;
         assert(p);
 
+        if (p->state != state)
+                bus_unit_send_pending_change_signal(UNIT(p), false);
+
         old_state = p->state;
         p->state = state;
 
index 151b8989a6416bb38bd7aada60a2ffdb6874636c..e478661f9486fb52849da49f4ebe745b27e3ce16 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "alloc-util.h"
 #include "dbus-scope.h"
+#include "dbus-unit.h"
 #include "load-dropin.h"
 #include "log.h"
 #include "scope.h"
@@ -82,6 +83,9 @@ static void scope_set_state(Scope *s, ScopeState state) {
         ScopeState old_state;
         assert(s);
 
+        if (s->state != state)
+                bus_unit_send_pending_change_signal(UNIT(s), false);
+
         old_state = s->state;
         s->state = state;
 
index 1fafb33f2371dc6cbbf0d1d1fd3dd04f1863da5a..d631687205e048b46e0791d366adb2d235667a77 100644 (file)
@@ -12,6 +12,7 @@
 #include "bus-kernel.h"
 #include "bus-util.h"
 #include "dbus-service.h"
+#include "dbus-unit.h"
 #include "def.h"
 #include "env-util.h"
 #include "escape.h"
@@ -1035,6 +1036,9 @@ static void service_set_state(Service *s, ServiceState state) {
 
         assert(s);
 
+        if (s->state != state)
+                bus_unit_send_pending_change_signal(UNIT(s), false);
+
         table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
 
         old_state = s->state;
index eae7295acb20a3f63efaef1a31ae2ee5597d599f..cb47ee8984b20322429ed25c51b98d6cdaa84bc5 100644 (file)
@@ -28,6 +28,7 @@
 #include "parse-util.h"
 #include "process-util.h"
 #include "reboot-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "switch-root.h"
@@ -443,13 +444,15 @@ int main(int argc, char *argv[]) {
         arguments[2] = NULL;
         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
 
+        (void) rlimit_nofile_safe();
+
         if (can_initrd) {
                 r = switch_root_initramfs();
                 if (r >= 0) {
                         argv[0] = (char*) "/shutdown";
 
-                        setsid();
-                        make_console_stdio();
+                        (void) setsid();
+                        (void) make_console_stdio();
 
                         log_info("Successfully changed into root pivot.\n"
                                  "Returning to initrd...");
index dc087680e1931dcc74feb701c9b55d7bd9b05e93..15b18bcad3562fb9876a80db1a452e73a1eca0ff 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "alloc-util.h"
 #include "dbus-slice.h"
+#include "dbus-unit.h"
 #include "log.h"
 #include "serialize.h"
 #include "slice.h"
@@ -29,6 +30,9 @@ static void slice_set_state(Slice *t, SliceState state) {
         SliceState old_state;
         assert(t);
 
+        if (t->state != state)
+                bus_unit_send_pending_change_signal(UNIT(t), false);
+
         old_state = t->state;
         t->state = state;
 
index f725c9eb009cdf7428722c3c6596bf352f086eef..dd126a7f21b7d06fe27f2ea3c9fde6452c63ef17 100644 (file)
@@ -17,6 +17,7 @@
 #include "bus-util.h"
 #include "copy.h"
 #include "dbus-socket.h"
+#include "dbus-unit.h"
 #include "def.h"
 #include "exit-status.h"
 #include "fd-util.h"
@@ -24,6 +25,7 @@
 #include "fs-util.h"
 #include "in-addr-util.h"
 #include "io-util.h"
+#include "ip-protocol-list.h"
 #include "label.h"
 #include "log.h"
 #include "missing.h"
@@ -35,7 +37,6 @@
 #include "serialize.h"
 #include "signal-util.h"
 #include "smack-util.h"
-#include "socket-protocol-list.h"
 #include "socket.h"
 #include "special.h"
 #include "string-table.h"
@@ -468,9 +469,7 @@ static int socket_verify(Socket *s) {
         return 0;
 }
 
-static void peer_address_hash_func(const void *p, struct siphash *state) {
-        const SocketPeer *s = p;
-
+static void peer_address_hash_func(const SocketPeer *s, struct siphash *state) {
         assert(s);
 
         if (s->peer.sa.sa_family == AF_INET)
@@ -483,8 +482,7 @@ static void peer_address_hash_func(const void *p, struct siphash *state) {
                 assert_not_reached("Unknown address family.");
 }
 
-static int peer_address_compare_func(const void *a, const void *b) {
-        const SocketPeer *x = a, *y = b;
+static int peer_address_compare_func(const SocketPeer *x, const SocketPeer *y) {
         int r;
 
         r = CMP(x->peer.sa.sa_family, y->peer.sa.sa_family);
@@ -502,10 +500,7 @@ static int peer_address_compare_func(const void *a, const void *b) {
         assert_not_reached("Black sheep in the family!");
 }
 
-const struct hash_ops peer_address_hash_ops = {
-        .hash = peer_address_hash_func,
-        .compare = peer_address_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(peer_address_hash_ops, SocketPeer, peer_address_hash_func, peer_address_compare_func);
 
 static int socket_load(Unit *u) {
         Socket *s = SOCKET(u);
@@ -814,7 +809,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
                 prefix, s->trigger_limit.burst);
 
-        str = socket_protocol_to_name(s->socket_protocol);
+        str = ip_protocol_to_name(s->socket_protocol);
         if (str)
                 fprintf(f, "%sSocketProtocol: %s\n", prefix, str);
 
@@ -1748,6 +1743,9 @@ static void socket_set_state(Socket *s, SocketState state) {
         SocketState old_state;
         assert(s);
 
+        if (s->state != state)
+                bus_unit_send_pending_change_signal(UNIT(s), false);
+
         old_state = s->state;
         s->state = state;
 
index db806fe0bb3bc8a2928f7bf1872ab8ce35273adb..2d8463b8b1812173ec019b0274eaf4d39799cff0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "alloc-util.h"
 #include "dbus-swap.h"
+#include "dbus-unit.h"
 #include "device-private.h"
 #include "device-util.h"
 #include "device.h"
@@ -272,77 +273,92 @@ static int swap_load_devnode(Swap *s) {
         return swap_set_devnode(s, p);
 }
 
-static int swap_load(Unit *u) {
+static int swap_add_extras(Swap *s) {
         int r;
-        Swap *s = SWAP(u);
 
         assert(s);
-        assert(u->load_state == UNIT_STUB);
 
-        /* Load a .swap file */
-        if (SWAP(u)->from_proc_swaps)
-                r = unit_load_fragment_and_dropin_optional(u);
-        else
-                r = unit_load_fragment_and_dropin(u);
+        if (UNIT(s)->fragment_path)
+                s->from_fragment = true;
+
+        if (!s->what) {
+                if (s->parameters_fragment.what)
+                        s->what = strdup(s->parameters_fragment.what);
+                else if (s->parameters_proc_swaps.what)
+                        s->what = strdup(s->parameters_proc_swaps.what);
+                else {
+                        r = unit_name_to_path(UNIT(s)->id, &s->what);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (!s->what)
+                        return -ENOMEM;
+        }
+
+        path_simplify(s->what, false);
+
+        if (!UNIT(s)->description) {
+                r = unit_set_description(UNIT(s), s->what);
+                if (r < 0)
+                        return r;
+        }
+
+        r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
         if (r < 0)
                 return r;
 
-        if (u->load_state == UNIT_LOADED) {
-
-                if (UNIT(s)->fragment_path)
-                        s->from_fragment = true;
+        r = swap_add_device_dependencies(s);
+        if (r < 0)
+                return r;
 
-                if (!s->what) {
-                        if (s->parameters_fragment.what)
-                                s->what = strdup(s->parameters_fragment.what);
-                        else if (s->parameters_proc_swaps.what)
-                                s->what = strdup(s->parameters_proc_swaps.what);
-                        else {
-                                r = unit_name_to_path(u->id, &s->what);
-                                if (r < 0)
-                                        return r;
-                        }
+        r = swap_load_devnode(s);
+        if (r < 0)
+                return r;
 
-                        if (!s->what)
-                                return -ENOMEM;
-                }
+        r = unit_patch_contexts(UNIT(s));
+        if (r < 0)
+                return r;
 
-                path_simplify(s->what, false);
+        r = unit_add_exec_dependencies(UNIT(s), &s->exec_context);
+        if (r < 0)
+                return r;
 
-                if (!UNIT(s)->description) {
-                        r = unit_set_description(u, s->what);
-                        if (r < 0)
-                                return r;
-                }
+        r = unit_set_default_slice(UNIT(s));
+        if (r < 0)
+                return r;
 
-                r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
-                if (r < 0)
-                        return r;
+        r = swap_add_default_dependencies(s);
+        if (r < 0)
+                return r;
 
-                r = swap_add_device_dependencies(s);
-                if (r < 0)
-                        return r;
+        return 0;
+}
 
-                r = swap_load_devnode(s);
-                if (r < 0)
-                        return r;
+static int swap_load(Unit *u) {
+        Swap *s = SWAP(u);
+        int r, q;
 
-                r = unit_patch_contexts(u);
-                if (r < 0)
-                        return r;
+        assert(s);
+        assert(u->load_state == UNIT_STUB);
 
-                r = unit_add_exec_dependencies(u, &s->exec_context);
-                if (r < 0)
-                        return r;
+        /* Load a .swap file */
+        if (SWAP(u)->from_proc_swaps)
+                r = unit_load_fragment_and_dropin_optional(u);
+        else
+                r = unit_load_fragment_and_dropin(u);
 
-                r = unit_set_default_slice(u);
-                if (r < 0)
-                        return r;
+        /* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is already
+         * active. */
+        if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
+                q = swap_add_extras(s);
+        else
+                q = 0;
 
-                r = swap_add_default_dependencies(s);
-                if (r < 0)
-                        return r;
-        }
+        if (r < 0)
+                return r;
+        if (q < 0)
+                return q;
 
         return swap_verify(s);
 }
@@ -369,7 +385,6 @@ static int swap_setup_unit(
                 return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
 
         u = manager_get_unit(m, e);
-
         if (u &&
             SWAP(u)->from_proc_swaps &&
             !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
@@ -404,6 +419,13 @@ static int swap_setup_unit(
                 }
         }
 
+        /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
+         * loaded. After all we can load it now, from the data in /proc/swaps. */
+        if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+                u->load_state = UNIT_LOADED;
+                u->load_error = 0;
+        }
+
         if (set_flags) {
                 SWAP(u)->is_active = true;
                 SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
@@ -471,7 +493,7 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f
                 swap_setup_unit(m, devlink, device, prio, set_flags);
         }
 
-        return r;
+        return 0;
 }
 
 static void swap_set_state(Swap *s, SwapState state) {
@@ -480,6 +502,9 @@ static void swap_set_state(Swap *s, SwapState state) {
 
         assert(s);
 
+        if (s->state != state)
+                bus_unit_send_pending_change_signal(UNIT(s), false);
+
         old_state = s->state;
         s->state = state;
 
@@ -809,6 +834,14 @@ fail:
         swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
 }
 
+static void swap_cycle_clear(Swap *s) {
+        assert(s);
+
+        s->result = SWAP_SUCCESS;
+        exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
+        UNIT(s)->reset_accounting = true;
+}
+
 static int swap_start(Unit *u) {
         Swap *s = SWAP(u), *other;
         int r;
@@ -848,11 +881,7 @@ static int swap_start(Unit *u) {
         if (r < 0)
                 return r;
 
-        s->result = SWAP_SUCCESS;
-        exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
-
-        u->reset_accounting = true;
-
+        swap_cycle_clear(s);
         swap_enter_activating(s);
         return 1;
 }
@@ -1084,7 +1113,6 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
 
 static int swap_load_proc_swaps(Manager *m, bool set_flags) {
         unsigned i;
-        int r = 0;
 
         assert(m);
 
@@ -1116,12 +1144,10 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
 
                 device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
 
-                k = swap_process_new(m, d, prio, set_flags);
-                if (k < 0)
-                        r = k;
+                (void) swap_process_new(m, d, prio, set_flags);
         }
 
-        return r;
+        return 0;
 }
 
 static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
@@ -1152,13 +1178,13 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
                 Swap *swap = SWAP(u);
 
                 if (!swap->is_active) {
-                        /* This has just been deactivated */
 
                         swap_unset_proc_swaps(swap);
 
                         switch (swap->state) {
 
                         case SWAP_ACTIVE:
+                                /* This has just been deactivated */
                                 swap_enter_dead(swap, SWAP_SUCCESS);
                                 break;
 
@@ -1179,7 +1205,8 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
 
                         case SWAP_DEAD:
                         case SWAP_FAILED:
-                                (void) unit_acquire_invocation_id(UNIT(swap));
+                                (void) unit_acquire_invocation_id(u);
+                                swap_cycle_clear(swap);
                                 swap_enter_active(swap, SWAP_SUCCESS);
                                 break;
 
index b8b8e32805eb0988b4a90150457c93dc2063abe6..421a304c73da421b14a962ab2cb35e962e23a248 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "dbus-target.h"
+#include "dbus-unit.h"
 #include "log.h"
 #include "serialize.h"
 #include "special.h"
@@ -18,6 +19,9 @@ static void target_set_state(Target *t, TargetState state) {
         TargetState old_state;
         assert(t);
 
+        if (t->state != state)
+                bus_unit_send_pending_change_signal(UNIT(t), false);
+
         old_state = t->state;
         t->state = state;
 
index 1527aab158279b9ce18c9e04658e261e09df15b2..d9ba2f76b3d3984d6745824ee74cc4abdea9185c 100644 (file)
@@ -6,6 +6,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "dbus-timer.h"
+#include "dbus-unit.h"
 #include "fs-util.h"
 #include "parse-util.h"
 #include "random-util.h"
@@ -247,6 +248,9 @@ static void timer_set_state(Timer *t, TimerState state) {
         TimerState old_state;
         assert(t);
 
+        if (t->state != state)
+                bus_unit_send_pending_change_signal(UNIT(t), false);
+
         old_state = t->state;
         t->state = state;
 
index bd4e4e7257dfd5a657220a820285dde05cf8dde1..7af0195aab83530247b6da40dae54a1089b84cd8 100644 (file)
@@ -25,6 +25,7 @@
 #include "linux-3.13/dm-ioctl.h"
 #include "mount-setup.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
index 547d9d885200b269a2ad25fae2d514c3e8e28af5..f57c099c39560c0e48790d78fd295e0d476a82b6 100644 (file)
@@ -286,35 +286,3 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
 
         return specifier_printf(format, table, u, ret);
 }
-
-int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
-        size_t n;
-        char **r, **i, **j;
-        int q;
-
-        /* Applies unit_full_printf to every entry in l */
-
-        assert(u);
-
-        n = strv_length(l);
-        r = new(char*, n+1);
-        if (!r)
-                return -ENOMEM;
-
-        for (i = l, j = r; *i; i++, j++) {
-                q = unit_full_printf(u, *i, j);
-                if (q < 0)
-                        goto fail;
-        }
-
-        *j = NULL;
-        *ret = r;
-        return 0;
-
-fail:
-        for (j--; j >= r; j--)
-                free(*j);
-
-        free(r);
-        return q;
-}
index 5bd1d77bb200d72289251a53e512a44ea529e389..f3dae159d5328cc7f075f602881a996c1103d6e5 100644 (file)
@@ -5,4 +5,3 @@
 
 int unit_name_printf(Unit *u, const char* text, char **ret);
 int unit_full_printf(Unit *u, const char *text, char **ret);
-int unit_full_printf_strv(Unit *u, char **l, char ***ret);
index 89bb95e2f1cf136d00b5098fd37770a3601df0d5..e1b6e9f11cc67a8f0ecc84672d575a811709caae 100644 (file)
@@ -22,6 +22,7 @@
 #include "execute.h"
 #include "fd-util.h"
 #include "fileio-label.h"
+#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "id128-util.h"
@@ -47,6 +48,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "umask-util.h"
 #include "unit-name.h"
 #include "unit.h"
@@ -1637,6 +1639,8 @@ static bool unit_condition_test(Unit *u) {
         dual_timestamp_get(&u->condition_timestamp);
         u->condition_result = unit_condition_test_list(u, u->conditions, condition_type_to_string);
 
+        unit_add_to_dbus_queue(u);
+
         return u->condition_result;
 }
 
@@ -1646,6 +1650,8 @@ static bool unit_assert_test(Unit *u) {
         dual_timestamp_get(&u->assert_timestamp);
         u->assert_result = unit_condition_test_list(u, u->asserts, assert_type_to_string);
 
+        unit_add_to_dbus_queue(u);
+
         return u->assert_result;
 }
 
@@ -2337,6 +2343,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
 
         m = u->manager;
 
+        /* Let's enqueue the change signal early. In case this unit has a job associated we want that this unit is in
+         * the bus queue, so that any job change signal queued will force out the unit change signal first. */
+        unit_add_to_dbus_queue(u);
+
         /* Update timestamps for state changes */
         if (!MANAGER_IS_RELOADING(m)) {
                 dual_timestamp_get(&u->state_change_timestamp);
@@ -2495,7 +2505,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
                 }
         }
 
-        unit_add_to_dbus_queue(u);
         unit_add_to_gc_queue(u);
 }
 
@@ -4928,7 +4937,7 @@ void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid) {
 
         r = unit_ref_uid_gid(u, uid, gid);
         if (r > 0)
-                bus_unit_send_change_signal(u);
+                unit_add_to_dbus_queue(u);
 }
 
 int unit_set_invocation_id(Unit *u, sd_id128_t id) {
@@ -4982,6 +4991,7 @@ int unit_acquire_invocation_id(Unit *u) {
         if (r < 0)
                 return log_unit_error_errno(u, r, "Failed to set invocation ID for unit: %m");
 
+        unit_add_to_dbus_queue(u);
         return 0;
 }
 
index 8c2cf7daa61bad6f5f13c36abc2a288b760e22ee..79d627c465cf28e3bf25a4412453a14af974091b 100644 (file)
@@ -46,6 +46,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index de26bee931e6eda5958fe38c96e8ef682579fcf5..fbee242962feb699c8360cf09edde25c16e2030e 100644 (file)
@@ -17,7 +17,6 @@
 #include "compress.h"
 #include "def.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "journal-internal.h"
 #include "journal-util.h"
@@ -35,6 +34,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 #include "verbs.h"
@@ -968,7 +968,7 @@ static int run_debug(int argc, char **argv, void *userdata) {
 
         fork_name = strjoina("(", arg_debugger, ")");
 
-        r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
+        r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 goto finish;
         if (r == 0) {
index b0b1065e2f9d2402bdc08cefdc677057e172d0b6..8a889e980a90f37175fb2010d314763bf79d0ae5 100644 (file)
@@ -13,6 +13,7 @@
 #include "hashmap.h"
 #include "id128-util.h"
 #include "log.h"
+#include "main-func.h"
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -40,6 +41,10 @@ static Hashmap *arg_disks = NULL;
 static char *arg_default_options = NULL;
 static char *arg_default_keyfile = NULL;
 
+STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
+
 static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
         _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -310,13 +315,16 @@ static int create_disk(
         return 0;
 }
 
-static void crypt_device_free(crypto_device *d) {
+static crypto_device* crypt_device_free(crypto_device *d) {
+        if (!d)
+                return NULL;
+
         free(d->uuid);
         free(d->keyfile);
         free(d->keydev);
         free(d->name);
         free(d->options);
-        free(d);
+        return mfree(d);
 }
 
 static crypto_device *get_crypto_device(const char *uuid) {
@@ -569,50 +577,40 @@ static int add_proc_cmdline_devices(void) {
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops, char, string_hash_func, string_compare_func,
+                                              crypto_device, crypt_device_free);
+
+static int run(int argc, char *argv[]) {
         int r;
 
-        if (argc > 1 && argc != 4) {
-                log_error("This program takes three or no arguments.");
-                return EXIT_FAILURE;
-        }
+        if (argc > 1 && argc != 4)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes three or no arguments.");
 
         if (argc > 1)
                 arg_dest = argv[1];
 
         log_setup_generator();
 
-        arg_disks = hashmap_new(&string_hash_ops);
-        if (!arg_disks) {
-                r = log_oom();
-                goto finish;
-        }
+        arg_disks = hashmap_new(&crypt_device_hash_ops);
+        if (!arg_disks)
+                return log_oom();
 
         r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
-        if (r < 0) {
-                log_warning_errno(r, "Failed to parse kernel command line: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse kernel command line: %m");
 
-        if (!arg_enabled) {
-                r = 0;
-                goto finish;
-        }
+        if (!arg_enabled)
+                return 0;
 
         r = add_crypttab_devices();
         if (r < 0)
-                goto finish;
+                return r;
 
         r = add_proc_cmdline_devices();
         if (r < 0)
-                goto finish;
-
-        r = 0;
-
-finish:
-        hashmap_free_with_destructor(arg_disks, crypt_device_free);
-        free(arg_default_options);
-        free(arg_default_keyfile);
+                return r;
 
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index 328f5654e88be779b40aa5b68986747d4108799d..379226641e5c31065944109eade7b89f2744bcef 100644 (file)
@@ -169,7 +169,7 @@ static int found_override(const char *top, const char *bottom) {
 
         fflush(stdout);
 
-        r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
+        r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
index 1719b69b98c41de66946daafa13ab494f4587b5b..9d64d95738c4eabb708848b2bb42b4eef193d198 100644 (file)
@@ -4,8 +4,8 @@
 
 #include "conf-files.h"
 #include "def.h"
+#include "env-file.h"
 #include "escape.h"
-#include "fileio.h"
 #include "log.h"
 #include "path-lookup.h"
 
index 8e429481f12399360a1a54af82c174b44785d73f..a3f4377a6415f613fe3874ab575f9943ef787907 100644 (file)
@@ -22,6 +22,7 @@
 #include "alloc-util.h"
 #include "ask-password-api.h"
 #include "copy.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
index 995cf92ef121cbd3ddfcfd75d1af26e68abf97a7..7fc4a283ce838ff762a1a7f91ef82261739a06e3 100644 (file)
@@ -27,6 +27,7 @@
 #include "path-util.h"
 #include "proc-cmdline.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
 #include "special.h"
@@ -401,6 +402,8 @@ static int run(int argc, char *argv[]) {
                 cmdline[i++] = device;
                 cmdline[i++] = NULL;
 
+                (void) rlimit_nofile_safe();
+
                 execv(cmdline[0], (char**) cmdline);
                 _exit(FSCK_OPERATIONAL_ERROR);
         }
index c74ad075c045a52cb9722a6cc5c52b808557296d..85cc36d80d5bc7ad8c52a003f5847dc324aae14a 100644 (file)
@@ -18,6 +18,7 @@
 #include "mkdir.h"
 #include "mount-setup.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index e40fe60bfbb1f31dbfe8ef8ace4ebaaddde76c7e..7ee97501418a3c5d749c004380359ff5051ca817 100644 (file)
@@ -2,9 +2,9 @@
 
 #include "catalog.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "fuzz.h"
+#include "tmpfile-util.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-catalog.XXXXXX";
index 95415d9f8524eddb6f724a6261800c67c1fe6cf9..8e3e850fbb96fd35b93ff82c5205aa727bfc9486 100644 (file)
@@ -1,13 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
-#include "fuzz.h"
 #include "fuzz-journald.h"
+#include "fuzz.h"
 #include "journald-native.h"
 #include "memfd-util.h"
 #include "process-util.h"
+#include "tmpfile-util.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         Server s;
index 247c0889bc8198362856c6da129cf23042e0f69c..5d6c8eb8ca059c73d698c2ea6e29d07dfeedf223 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <linux/sockios.h>
+#include <sys/ioctl.h>
 
 #include "fd-util.h"
 #include "fuzz.h"
index 389b545ac27ce14801d07727e5b8e394f0153bb3..3a1e60fc5dd4db82f286a94449c4ff45ea8eb8ed 100644 (file)
@@ -1,7 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <netinet/icmp6.h>
 #include <arpa/inet.h>
+#include <netinet/icmp6.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "icmp6-util.h"
index 1ca071e9991686742d5a3debabc2f0f1f70f24fe..d1889273986dc4e81461ddecafc87e4b38d16968 100644 (file)
@@ -23,7 +23,7 @@
 #include "gpt.h"
 #include "missing.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index d14073ace052a07a7692dd6ab844ab6fcf3995b4..c1f9e27523fa2c2e963a2218b4f278a66856a8c7 100644 (file)
@@ -9,11 +9,15 @@
 #include "bus-common-errors.h"
 #include "bus-util.h"
 #include "def.h"
+#include "env-file-label.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fileio-label.h"
+#include "fileio.h"
 #include "hostname-util.h"
 #include "id128-util.h"
 #include "main-func.h"
+#include "missing_capability.h"
 #include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
index 04ad129ca138a934c4fe87e3cb46296ee8b435cb..6a02b47a1745577ebb3415b7bffede7bcc28b579 100644 (file)
 #include "copy.h"
 #include "export-raw.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "import-common.h"
 #include "missing.h"
 #include "ratelimit.h"
 #include "stat-util.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
index 5acb09432a69ea4537546277df108d2021df6a47..ed546769f340c611eeb5882fa145f6b775424aaf 100644 (file)
@@ -6,11 +6,11 @@
 #include "btrfs-util.h"
 #include "export-tar.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "import-common.h"
 #include "process-util.h"
 #include "ratelimit.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
@@ -141,6 +141,26 @@ static void tar_export_report_progress(TarExport *e) {
         e->last_percent = percent;
 }
 
+static int tar_export_finish(TarExport *e) {
+        int r;
+
+        assert(e);
+        assert(e->tar_fd >= 0);
+
+        if (e->tar_pid > 0) {
+                r = wait_for_terminate_and_check("tar", e->tar_pid, WAIT_LOG);
+                e->tar_pid = 0;
+                if (r < 0)
+                        return r;
+                if (r != EXIT_SUCCESS)
+                        return -EPROTO;
+        }
+
+        e->tar_fd = safe_close(e->tar_fd);
+
+        return 0;
+}
+
 static int tar_export_process(TarExport *e) {
         ssize_t l;
         int r;
@@ -156,7 +176,7 @@ static int tar_export_process(TarExport *e) {
 
                         e->tried_splice = true;
                 } else if (l == 0) {
-                        r = 0;
+                        r = tar_export_finish(e);
                         goto finish;
                 } else {
                         e->written_uncompressed += l;
@@ -172,7 +192,7 @@ static int tar_export_process(TarExport *e) {
                 uint8_t input[COPY_BUFFER_SIZE];
 
                 if (e->eof) {
-                        r = 0;
+                        r = tar_export_finish(e);
                         goto finish;
                 }
 
index f81485bbc7db4b5093a403e91b18752ee48743d3..490710678f7a54fd75e28a37034e4adf293ca801 100644 (file)
@@ -95,7 +95,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
 
                 fd = STDOUT_FILENO;
 
-                (void) readlink_malloc("/proc/self/fd/1", &pretty);
+                (void) fd_get_path(fd, &pretty);
                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
         }
 
@@ -172,7 +172,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
 
                 fd = STDOUT_FILENO;
 
-                (void) readlink_malloc("/proc/self/fd/1", &pretty);
+                (void) fd_get_path(fd, &pretty);
                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
         }
 
index e2de2c2dd061ce12dfb4beb1fd67378375a3b26d..89f03010d1349a972e9097f1b12b32d659d0936c 100644 (file)
@@ -5,12 +5,18 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "btrfs-util.h"
 #include "capability-util.h"
+#include "dirent-util.h"
 #include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "import-common.h"
+#include "os-util.h"
 #include "process-util.h"
 #include "signal-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 int import_make_read_only_fd(int fd) {
@@ -147,3 +153,107 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
 
         return TAKE_FD(pipefd[0]);
 }
+
+int import_mangle_os_tree(const char *path) {
+        _cleanup_closedir_ DIR *d = NULL, *cd = NULL;
+        _cleanup_free_ char *child = NULL, *t = NULL;
+        const char *joined;
+        struct dirent *de;
+        int r;
+
+        assert(path);
+
+        /* Some tarballs contain a single top-level directory that contains the actual OS directory tree. Try to
+         * recognize this, and move the tree one level up. */
+
+        r = path_is_os_tree(path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine whether '%s' is an OS tree: %m", path);
+        if (r > 0) {
+                log_debug("Directory tree '%s' is a valid OS tree.", path);
+                return 0;
+        }
+
+        log_debug("Directory tree '%s' is not recognizable as OS tree, checking whether to rearrange it.", path);
+
+        d = opendir(path);
+        if (!d)
+                return log_error_errno(r, "Failed to open directory '%s': %m", path);
+
+        errno = 0;
+        de = readdir_no_dot(d);
+        if (!de) {
+                if (errno != 0)
+                        return log_error_errno(errno, "Failed to iterate through directory '%s': %m", path);
+
+                log_debug("Directory '%s' is empty, leaving it as it is.", path);
+                return 0;
+        }
+
+        child = strdup(de->d_name);
+        if (!child)
+                return log_oom();
+
+        errno = 0;
+        de = readdir_no_dot(d);
+        if (de) {
+                if (errno != 0)
+                        return log_error_errno(errno, "Failed to iterate through directory '%s': %m", path);
+
+                log_debug("Directory '%s' does not look like a directory tree, and has multiple children, leaving as it is.", path);
+                return 0;
+        }
+
+        joined = strjoina(path, "/", child);
+        r = path_is_os_tree(joined);
+        if (r == -ENOTDIR) {
+                log_debug("Directory '%s' does not look like a directory tree, and contains a single regular file only, leaving as it is.", path);
+                return 0;
+        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine whether '%s' is an OS tree: %m", joined);
+        if (r == 0) {
+                log_debug("Neither '%s' nor '%s' is a valid OS tree, leaving them as they are.", path, joined);
+                return 0;
+        }
+
+        /* Nice, we have checked now:
+         *
+         * 1. The top-level directory does not qualify as OS tree
+         * 1. The top-level directory only contains one item
+         * 2. That item is a directory
+         * 3. And that directory qualifies as OS tree
+         *
+         * Let's now rearrange things, moving everything in the inner directory one level up */
+
+        cd = xopendirat(dirfd(d), child, O_NOFOLLOW);
+        if (!cd)
+                return log_error_errno(errno, "Can't open directory '%s': %m", joined);
+
+        log_info("Rearranging '%s', moving OS tree one directory up.", joined);
+
+        /* Let's rename the child to an unguessable name so that we can be sure all files contained in it can be
+         * safely moved up and won't collide with the name. */
+        r = tempfn_random(child, NULL, &t);
+        if (r < 0)
+                return log_oom();
+        r = rename_noreplace(dirfd(d), child, dirfd(d), t);
+        if (r < 0)
+                return log_error_errno(r, "Unable to rename '%s' to '%s/%s': %m", joined, path, t);
+
+        FOREACH_DIRENT_ALL(de, cd, return log_error_errno(errno, "Failed to iterate through directory '%s': %m", joined)) {
+                if (dot_or_dot_dot(de->d_name))
+                        continue;
+
+                r = rename_noreplace(dirfd(cd), de->d_name, dirfd(d), de->d_name);
+                if (r < 0)
+                        return log_error_errno(r, "Unable to move '%s/%s/%s' to '%s/%s': %m", path, t, de->d_name, path, de->d_name);
+        }
+
+        if (unlinkat(dirfd(d), t, AT_REMOVEDIR) < 0)
+                return log_error_errno(errno, "Failed to remove temporary directory '%s/%s': %m", path, t);
+
+        log_info("Successfully rearranged OS tree.");
+
+        return 0;
+}
index 99ac5fe970d9c40a795939c075b37eab678deab2..94d224f4129889b557cfd9f8463a403748b680a8 100644 (file)
@@ -1,8 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <sys/types.h>
+
 int import_make_read_only_fd(int fd);
 int import_make_read_only(const char *path);
 
 int import_fork_tar_c(const char *path, pid_t *ret);
 int import_fork_tar_x(const char *path, pid_t *ret);
+
+int import_mangle_os_tree(const char *path);
diff --git a/src/import/import-fs.c b/src/import/import-fs.c
new file mode 100644 (file)
index 0000000..35ba6ba
--- /dev/null
@@ -0,0 +1,327 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "alloc-util.h"
+#include "btrfs-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
+#include "machine-image.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "tmpfile-util.h"
+#include "verbs.h"
+
+static bool arg_force = false;
+static bool arg_read_only = false;
+static const char *arg_image_root = "/var/lib/machines";
+
+typedef struct ProgressInfo {
+        RateLimit limit;
+        char *path;
+        uint64_t size;
+        bool started;
+        bool logged_incomplete;
+} ProgressInfo;
+
+static volatile sig_atomic_t cancelled = false;
+
+static void sigterm_sigint(int sig) {
+        cancelled = true;
+}
+
+static void progress_info_free(ProgressInfo *p) {
+        free(p->path);
+}
+
+static void progress_show(ProgressInfo *p) {
+        assert(p);
+
+        /* Show progress only every now and then. */
+        if (!ratelimit_below(&p->limit))
+                return;
+
+        /* Suppress the first message, start with the second one */
+        if (!p->started) {
+                p->started = true;
+                return;
+        }
+
+        /* Mention the list is incomplete before showing first output. */
+        if (!p->logged_incomplete) {
+                log_notice("(Note, file list shown below is incomplete, and is intended as sporadic progress report only.)");
+                p->logged_incomplete = true;
+        }
+
+        if (p->size == 0)
+                log_info("Copying tree, currently at '%s'...", p->path);
+        else {
+                char buffer[FORMAT_BYTES_MAX];
+
+                log_info("Copying tree, currently at '%s' (@%s)...", p->path, format_bytes(buffer, sizeof(buffer), p->size));
+        }
+}
+
+static int progress_path(const char *path, const struct stat *st, void *userdata) {
+        ProgressInfo *p = userdata;
+        int r;
+
+        assert(p);
+
+        if (cancelled)
+                return -EOWNERDEAD;
+
+        r = free_and_strdup(&p->path, path);
+        if (r < 0)
+                return r;
+
+        p->size = 0;
+
+        progress_show(p);
+        return 0;
+}
+
+static int progress_bytes(uint64_t nbytes, void *userdata) {
+        ProgressInfo *p = userdata;
+
+        assert(p);
+        assert(p->size != UINT64_MAX);
+
+        if (cancelled)
+                return -EOWNERDEAD;
+
+        p->size += nbytes;
+
+        progress_show(p);
+        return 0;
+}
+
+static int import_fs(int argc, char *argv[], void *userdata) {
+        _cleanup_(rm_rf_subvolume_and_freep) char *temp_path = NULL;
+        _cleanup_(progress_info_free) ProgressInfo progress = {};
+        const char *path = NULL, *local = NULL, *final_path;
+        _cleanup_close_ int open_fd = -1;
+        struct sigaction old_sigint_sa, old_sigterm_sa;
+        static const struct sigaction sa = {
+                .sa_handler = sigterm_sigint,
+                .sa_flags = SA_RESTART,
+        };
+        int r, fd;
+
+        if (argc >= 2)
+                path = argv[1];
+        if (isempty(path) || streq(path, "-"))
+                path = NULL;
+
+        if (argc >= 3)
+                local = argv[2];
+        else if (path)
+                local = basename(path);
+        if (isempty(local) || streq(local, "-"))
+                local = NULL;
+
+        if (local) {
+                if (!machine_name_is_valid(local)) {
+                        log_error("Local image name '%s' is not valid.", local);
+                        return -EINVAL;
+                }
+
+                if (!arg_force) {
+                        r = image_find(IMAGE_MACHINE, local, NULL);
+                        if (r < 0) {
+                                if (r != -ENOENT)
+                                        return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
+                        } else {
+                                log_error("Image '%s' already exists.", local);
+                                return -EEXIST;
+                        }
+                }
+        } else
+                local = "imported";
+
+        if (path) {
+                open_fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+                if (open_fd < 0)
+                        return log_error_errno(errno, "Failed to open directory to import: %m");
+
+                fd = open_fd;
+
+                log_info("Importing '%s', saving as '%s'.", path, local);
+        } else {
+                _cleanup_free_ char *pretty = NULL;
+
+                fd = STDIN_FILENO;
+
+                (void) fd_get_path(fd, &pretty);
+                log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
+        }
+
+        final_path = strjoina(arg_image_root, "/", local);
+
+        r = tempfn_random(final_path, NULL, &temp_path);
+        if (r < 0)
+                return log_oom();
+
+        (void) mkdir_parents_label(temp_path, 0700);
+
+        RATELIMIT_INIT(progress.limit, 200*USEC_PER_MSEC, 1);
+
+        /* Hook into SIGINT/SIGTERM, so that we can cancel things then */
+        assert(sigaction(SIGINT, &sa, &old_sigint_sa) >= 0);
+        assert(sigaction(SIGTERM, &sa, &old_sigterm_sa) >= 0);
+
+        r = btrfs_subvol_snapshot_fd_full(
+                        fd,
+                        temp_path,
+                        BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|BTRFS_SNAPSHOT_QUOTA,
+                        progress_path,
+                        progress_bytes,
+                        &progress);
+        if (r == -EOWNERDEAD) { /* SIGINT + SIGTERM cause this, see signal handler above */
+                log_error("Copy cancelled.");
+                goto finish;
+        }
+        if (r < 0) {
+                log_error_errno(r, "Failed to copy directory: %m");
+                goto finish;
+        }
+
+        r = import_mangle_os_tree(temp_path);
+        if (r < 0)
+                goto finish;
+
+        (void) import_assign_pool_quota_and_warn(temp_path);
+
+        if (arg_read_only) {
+                r = import_make_read_only(temp_path);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to make directory read-only: %m");
+                        goto finish;
+                }
+        }
+
+        if (arg_force)
+                (void) rm_rf(final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+
+        r = rename_noreplace(AT_FDCWD, temp_path, AT_FDCWD, final_path);
+        if (r < 0) {
+                log_error_errno(r, "Failed to move image into place: %m");
+                goto finish;
+        }
+
+        temp_path = mfree(temp_path);
+
+        log_info("Exiting.");
+
+finish:
+        /* Put old signal handlers into place */
+        assert(sigaction(SIGINT, &old_sigint_sa, NULL) >= 0);
+        assert(sigaction(SIGTERM, &old_sigterm_sa, NULL) >= 0);
+
+        return 0;
+}
+
+static int help(int argc, char *argv[], void *userdata) {
+
+        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+               "Import container images from a file system.\n\n"
+               "  -h --help                   Show this help\n"
+               "     --version                Show package version\n"
+               "     --force                  Force creation of image\n"
+               "     --image-root=PATH        Image root directory\n"
+               "     --read-only              Create a read-only image\n\n"
+               "Commands:\n"
+               "  run DIRECTORY [NAME]             Import a directory\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_FORCE,
+                ARG_IMAGE_ROOT,
+                ARG_READ_ONLY,
+        };
+
+        static const struct option options[] = {
+                { "help",            no_argument,       NULL, 'h'                 },
+                { "version",         no_argument,       NULL, ARG_VERSION         },
+                { "force",           no_argument,       NULL, ARG_FORCE           },
+                { "image-root",      required_argument, NULL, ARG_IMAGE_ROOT      },
+                { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
+                switch (c) {
+
+                case 'h':
+                        return help(0, NULL, NULL);
+
+                case ARG_VERSION:
+                        return version();
+
+                case ARG_FORCE:
+                        arg_force = true;
+                        break;
+
+                case ARG_IMAGE_ROOT:
+                        arg_image_root = optarg;
+                        break;
+
+                case ARG_READ_ONLY:
+                        arg_read_only = true;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        return 1;
+}
+
+static int import_fs_main(int argc, char *argv[]) {
+
+        static const Verb verbs[] = {
+                { "help", VERB_ANY, VERB_ANY, 0, help      },
+                { "run",  2,        3,        0, import_fs },
+                {}
+        };
+
+        return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+
+        setlocale(LC_ALL, "");
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        r = import_fs_main(argc, argv);
+
+finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
index e8adaae74096e2565f68698c73fe1e74a87c2a28..4b1161557ddc28656428415b35bcb16d2581d9fe 100644 (file)
@@ -10,7 +10,6 @@
 #include "chattr-util.h"
 #include "copy.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "hostname-util.h"
 #include "import-common.h"
@@ -24,6 +23,7 @@
 #include "ratelimit.h"
 #include "rm-rf.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 struct RawImport {
@@ -37,7 +37,6 @@ struct RawImport {
         char *local;
         bool force_local;
         bool read_only;
-        bool grow_machine_directory;
 
         char *temp_path;
         char *final_path;
@@ -47,8 +46,6 @@ struct RawImport {
 
         ImportCompress compress;
 
-        uint64_t written_since_last_grow;
-
         sd_event_source *input_event_source;
 
         uint8_t buffer[16*1024];
@@ -95,7 +92,6 @@ int raw_import_new(
 
         _cleanup_(raw_import_unrefp) RawImport *i = NULL;
         _cleanup_free_ char *root = NULL;
-        bool grow;
         int r;
 
         assert(ret);
@@ -104,8 +100,6 @@ int raw_import_new(
         if (!root)
                 return -ENOMEM;
 
-        grow = path_startswith(root, "/var/lib/machines");
-
         i = new(RawImport, 1);
         if (!i)
                 return -ENOMEM;
@@ -117,7 +111,6 @@ int raw_import_new(
                 .userdata = userdata,
                 .last_percent = (unsigned) -1,
                 .image_root = TAKE_PTR(root),
-                .grow_machine_directory = grow,
         };
 
         RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
@@ -307,11 +300,6 @@ static int raw_import_write(const void *p, size_t sz, void *userdata) {
         RawImport *i = userdata;
         ssize_t n;
 
-        if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
-                i->written_since_last_grow = 0;
-                grow_machine_directory();
-        }
-
         n = sparse_write(i->output_fd, p, sz, 64);
         if (n < 0)
                 return (int) n;
@@ -319,7 +307,6 @@ static int raw_import_write(const void *p, size_t sz, void *userdata) {
                 return -EIO;
 
         i->written_uncompressed += sz;
-        i->written_since_last_grow += sz;
 
         return 0;
 }
index 0399b03747f8f2fe3dd6b1934724b9efaa13140b..4d0d9254d0125888f11482fa160f9d167b38fd05 100644 (file)
@@ -24,6 +24,7 @@
 #include "ratelimit.h"
 #include "rm-rf.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 struct TarImport {
@@ -37,7 +38,6 @@ struct TarImport {
         char *local;
         bool force_local;
         bool read_only;
-        bool grow_machine_directory;
 
         char *temp_path;
         char *final_path;
@@ -47,8 +47,6 @@ struct TarImport {
 
         ImportCompress compress;
 
-        uint64_t written_since_last_grow;
-
         sd_event_source *input_event_source;
 
         uint8_t buffer[16*1024];
@@ -102,7 +100,6 @@ int tar_import_new(
 
         _cleanup_(tar_import_unrefp) TarImport *i = NULL;
         _cleanup_free_ char *root = NULL;
-        bool grow;
         int r;
 
         assert(ret);
@@ -111,8 +108,6 @@ int tar_import_new(
         if (!root)
                 return -ENOMEM;
 
-        grow = path_startswith(root, "/var/lib/machines");
-
         i = new(TarImport, 1);
         if (!i)
                 return -ENOMEM;
@@ -124,7 +119,6 @@ int tar_import_new(
                 .userdata = userdata,
                 .last_percent = (unsigned) -1,
                 .image_root = TAKE_PTR(root),
-                .grow_machine_directory = grow,
         };
 
         RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
@@ -182,8 +176,14 @@ static int tar_import_finish(TarImport *i) {
                 i->tar_pid = 0;
                 if (r < 0)
                         return r;
+                if (r != EXIT_SUCCESS)
+                        return -EPROTO;
         }
 
+        r = import_mangle_os_tree(i->temp_path);
+        if (r < 0)
+                return r;
+
         if (i->read_only) {
                 r = import_make_read_only(i->temp_path);
                 if (r < 0)
@@ -241,17 +241,11 @@ static int tar_import_write(const void *p, size_t sz, void *userdata) {
         TarImport *i = userdata;
         int r;
 
-        if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
-                i->written_since_last_grow = 0;
-                grow_machine_directory();
-        }
-
         r = loop_write(i->tar_fd, p, sz, false);
         if (r < 0)
                 return r;
 
         i->written_uncompressed += sz;
-        i->written_since_last_grow += sz;
 
         return 0;
 }
index 9dca2f3d415669425000d86fc3904953e0a2ad90..f34244acff2e71f81879cecf1f457204d7a49bb0 100644 (file)
@@ -96,7 +96,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
                 fd = STDIN_FILENO;
 
-                (void) readlink_malloc("/proc/self/fd/0", &pretty);
+                (void) fd_get_path(fd, &pretty);
                 log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
         }
 
@@ -192,7 +192,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
 
                 fd = STDIN_FILENO;
 
-                (void) readlink_malloc("/proc/self/fd/0", &pretty);
+                (void) fd_get_path(fd, &pretty);
                 log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
         }
 
index 2c88d353da0a96f1506f87dc1b488f0902225164..2426933558f3737e1192e9556b4d4da75f302b36 100644 (file)
@@ -10,6 +10,7 @@
 #include "bus-util.h"
 #include "def.h"
 #include "fd-util.h"
+#include "float.h"
 #include "hostname-util.h"
 #include "import-util.h"
 #include "machine-pool.h"
@@ -21,6 +22,7 @@
 #include "process-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "stat-util.h"
 #include "string-table.h"
 #include "strv.h"
 #include "syslog-util.h"
@@ -34,6 +36,7 @@ typedef struct Manager Manager;
 typedef enum TransferType {
         TRANSFER_IMPORT_TAR,
         TRANSFER_IMPORT_RAW,
+        TRANSFER_IMPORT_FS,
         TRANSFER_EXPORT_TAR,
         TRANSFER_EXPORT_RAW,
         TRANSFER_PULL_TAR,
@@ -94,6 +97,7 @@ struct Manager {
 static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
         [TRANSFER_IMPORT_TAR] = "import-tar",
         [TRANSFER_IMPORT_RAW] = "import-raw",
+        [TRANSFER_IMPORT_FS] = "import-fs",
         [TRANSFER_EXPORT_TAR] = "export-tar",
         [TRANSFER_EXPORT_RAW] = "export-raw",
         [TRANSFER_PULL_TAR] = "pull-tar",
@@ -156,6 +160,7 @@ static int transfer_new(Manager *m, Transfer **ret) {
                 .stdin_fd = -1,
                 .stdout_fd = -1,
                 .verify = _IMPORT_VERIFY_INVALID,
+                .progress_percent= (unsigned) -1,
         };
 
         id = m->current_transfer_id + 1;
@@ -177,6 +182,15 @@ static int transfer_new(Manager *m, Transfer **ret) {
         return 0;
 }
 
+static double transfer_percent_as_double(Transfer *t) {
+        assert(t);
+
+        if (t->progress_percent == (unsigned) -1)
+                return -DBL_MAX;
+
+        return (double) t->progress_percent / 100.0;
+}
+
 static void transfer_send_log_line(Transfer *t, const char *line) {
         int r, priority = LOG_INFO;
 
@@ -196,7 +210,7 @@ static void transfer_send_log_line(Transfer *t, const char *line) {
                         priority,
                         line);
         if (r < 0)
-                log_error_errno(r, "Cannot emit message: %m");
+                log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
  }
 
 static void transfer_send_logs(Transfer *t, bool flush) {
@@ -301,17 +315,16 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda
 
         if (si->si_code == CLD_EXITED) {
                 if (si->si_status != 0)
-                        log_error("Import process failed with exit code %i.", si->si_status);
+                        log_error("Transfer process failed with exit code %i.", si->si_status);
                 else {
-                        log_debug("Import process succeeded.");
+                        log_debug("Transfer process succeeded.");
                         success = true;
                 }
 
         } 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));
+                log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status));
         else
-                log_error("Import process failed due to unknown reason.");
+                log_error("Transfer process failed due to unknown reason.");
 
         t->pid = 0;
 
@@ -326,14 +339,12 @@ static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *u
         assert(t);
 
         l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
+        if (l < 0)
+                log_error_errno(errno, "Failed to read log message: %m");
         if (l <= 0) {
                 /* EOF/read error. We just close the pipe here, and
                  * close the watch, waiting for the SIGCHLD to arrive,
                  * before we do anything else. */
-
-                if (l < 0)
-                        log_error_errno(errno, "Failed to read log message: %m");
-
                 t->log_event_source = sd_event_source_unref(t->log_event_source);
                 return 0;
         }
@@ -360,7 +371,7 @@ static int transfer_start(Transfer *t) {
                 return r;
         if (r == 0) {
                 const char *cmd[] = {
-                        NULL, /* systemd-import, systemd-export or systemd-pull */
+                        NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
                         NULL, /* tar, raw  */
                         NULL, /* --verify= */
                         NULL, /* verify argument */
@@ -393,17 +404,52 @@ static int transfer_start(Transfer *t) {
                         _exit(EXIT_FAILURE);
                 }
 
-                if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_IMPORT_RAW))
+                switch (t->type) {
+
+                case TRANSFER_IMPORT_TAR:
+                case TRANSFER_IMPORT_RAW:
                         cmd[k++] = SYSTEMD_IMPORT_PATH;
-                else if (IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW))
+                        break;
+
+                case TRANSFER_IMPORT_FS:
+                        cmd[k++] = SYSTEMD_IMPORT_FS_PATH;
+                        break;
+
+                case TRANSFER_EXPORT_TAR:
+                case TRANSFER_EXPORT_RAW:
                         cmd[k++] = SYSTEMD_EXPORT_PATH;
-                else
+                        break;
+
+                case TRANSFER_PULL_TAR:
+                case TRANSFER_PULL_RAW:
                         cmd[k++] = SYSTEMD_PULL_PATH;
+                        break;
+
+                default:
+                        assert_not_reached("Unexpected transfer type");
+                }
 
-                if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_EXPORT_TAR, TRANSFER_PULL_TAR))
+                switch (t->type) {
+
+                case TRANSFER_IMPORT_TAR:
+                case TRANSFER_EXPORT_TAR:
+                case TRANSFER_PULL_TAR:
                         cmd[k++] = "tar";
-                else
+                        break;
+
+                case TRANSFER_IMPORT_RAW:
+                case TRANSFER_EXPORT_RAW:
+                case TRANSFER_PULL_RAW:
                         cmd[k++] = "raw";
+                        break;
+
+                case TRANSFER_IMPORT_FS:
+                        cmd[k++] = "run";
+                        break;
+
+                default:
+                        break;
+                }
 
                 if (t->verify != _IMPORT_VERIFY_INVALID) {
                         cmd[k++] = "--verify";
@@ -513,7 +559,6 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
         struct ucred *ucred = NULL;
         Manager *m = userdata;
         struct cmsghdr *cmsg;
-        unsigned percent;
         char *p, *e;
         Transfer *t;
         Iterator i;
@@ -569,15 +614,15 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
         e = strchrnul(p, '\n');
         *e = 0;
 
-        r = safe_atou(p, &percent);
-        if (r < 0 || percent > 100) {
+        r = parse_percent(p);
+        if (r < 0) {
                 log_warning("Got invalid percent value, ignoring.");
                 return 0;
         }
 
-        t->progress_percent = percent;
+        t->progress_percent = (unsigned) r;
 
-        log_debug("Got percentage from client: %u%%", percent);
+        log_debug("Got percentage from client: %u%%", t->progress_percent);
         return 0;
 }
 
@@ -636,12 +681,9 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *remote)
         assert(type >= 0);
         assert(type < _TRANSFER_TYPE_MAX);
 
-        HASHMAP_FOREACH(t, m->transfers, i) {
-
-                if (t->type == type &&
-                    streq_ptr(t->remote, remote))
+        HASHMAP_FOREACH(t, m->transfers, i)
+                if (t->type == type && streq_ptr(t->remote, remote))
                         return t;
-        }
 
         return NULL;
 }
@@ -675,10 +717,14 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         if (r < 0)
                 return r;
 
+        r = fd_verify_regular(fd);
+        if (r < 0)
+                return r;
+
         if (!machine_name_is_valid(local))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
 
-        r = setup_machine_directory((uint64_t) -1, error);
+        r = setup_machine_directory(error);
         if (r < 0)
                 return r;
 
@@ -711,6 +757,72 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         return sd_bus_reply_method_return(msg, "uo", id, object);
 }
 
+static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+        _cleanup_(transfer_unrefp) Transfer *t = NULL;
+        int fd, force, read_only, r;
+        const char *local, *object;
+        Manager *m = userdata;
+        uint32_t id;
+
+        assert(msg);
+        assert(m);
+
+        r = bus_verify_polkit_async(
+                        msg,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.import1.import",
+                        NULL,
+                        false,
+                        UID_INVALID,
+                        &m->polkit_registry,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Will call us back */
+
+        r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
+        if (r < 0)
+                return r;
+
+        r = fd_verify_directory(fd);
+        if (r < 0)
+                return r;
+
+        if (!machine_name_is_valid(local))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+
+        r = setup_machine_directory(error);
+        if (r < 0)
+                return r;
+
+        r = transfer_new(m, &t);
+        if (r < 0)
+                return r;
+
+        t->type = TRANSFER_IMPORT_FS;
+        t->force_local = force;
+        t->read_only = read_only;
+
+        t->local = strdup(local);
+        if (!t->local)
+                return -ENOMEM;
+
+        t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+        if (t->stdin_fd < 0)
+                return -errno;
+
+        r = transfer_start(t);
+        if (r < 0)
+                return r;
+
+        object = t->object_path;
+        id = t->id;
+        t = NULL;
+
+        return sd_bus_reply_method_return(msg, "uo", id, object);
+}
+
 static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         int fd, r;
@@ -743,6 +855,10 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         if (!machine_name_is_valid(local))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
 
+        r = fd_verify_regular(fd);
+        if (r < 0)
+                return r;
+
         type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
 
         r = transfer_new(m, &t);
@@ -821,7 +937,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
         if (v < 0)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
 
-        r = setup_machine_directory((uint64_t) -1, error);
+        r = setup_machine_directory(error);
         if (r < 0)
                 return r;
 
@@ -886,7 +1002,7 @@ static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_err
                                 transfer_type_to_string(t->type),
                                 t->remote,
                                 t->local,
-                                (double) t->progress_percent / 100.0,
+                                transfer_percent_as_double(t),
                                 t->object_path);
                 if (r < 0)
                         return r;
@@ -982,7 +1098,7 @@ static int property_get_progress(
         assert(reply);
         assert(t);
 
-        return sd_bus_message_append(reply, "d", (double) t->progress_percent / 100.0);
+        return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
 }
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
@@ -1005,6 +1121,7 @@ static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ImportFileSystem", "hsbb", "uo", method_import_fs, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
index 283ba08c676b0672efc05288fa8f50a12f7e5537..1c15fd883fec6761499a6280cbb67c9db6e57c9a 100644 (file)
@@ -38,6 +38,12 @@ systemd_import_sources = files('''
         qcow2-util.h
 '''.split())
 
+systemd_import_fs_sources = files('''
+        import-fs.c
+        import-common.c
+        import-common.h
+'''.split())
+
 systemd_export_sources = files('''
         export.c
         export-tar.c
index 9889cd6b109aae1877be0605df4184774e93ddcb..2fdb2ba77c5fd0197abb2b0d894823751c68315b 100644 (file)
                        send_interface="org.freedesktop.import1.Manager"
                        send_member="CancelTransfer"/>
 
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="ImportTar"/>
+
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="ImportRaw"/>
+
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="ImportFileSystem"/>
+
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="ExportTar"/>
+
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="ExportRaw"/>
+
                 <allow send_destination="org.freedesktop.import1"
                        send_interface="org.freedesktop.import1.Manager"
                        send_member="PullTar"/>
index a90693c802b83be1a936e557ea596e28897dc577..acfe3809695dc9324f42fc95ee469349d90f91ec 100644 (file)
@@ -14,6 +14,7 @@
 #include "process-util.h"
 #include "pull-common.h"
 #include "pull-job.h"
+#include "rlimit-util.h"
 #include "rm-rf.h"
 #include "signal-util.h"
 #include "siphash24.h"
@@ -472,6 +473,8 @@ int pull_verify(PullJob *main_job,
                         _exit(EXIT_FAILURE);
                 }
 
+                (void) rlimit_nofile_safe();
+
                 cmd[k++] = strjoina("--homedir=", gpg_home);
 
                 /* We add the user keyring only to the command line
index 0b7d9df32dc6fa922ce3c62256a42c617e4be151..a44e0a7eda9e305b4f6290cee36a4d89950ccd68 100644 (file)
@@ -74,7 +74,6 @@ static int pull_job_restart(PullJob *j) {
         j->payload_allocated = 0;
         j->written_compressed = 0;
         j->written_uncompressed = 0;
-        j->written_since_last_grow = 0;
 
         r = pull_job_begin(j);
         if (r < 0)
@@ -224,11 +223,6 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata)
 
         if (j->disk_fd >= 0) {
 
-                if (j->grow_machine_directory && j->written_since_last_grow >= GROW_INTERVAL_BYTES) {
-                        j->written_since_last_grow = 0;
-                        grow_machine_directory();
-                }
-
                 if (j->allow_sparse)
                         n = sparse_write(j->disk_fd, p, sz, 64);
                 else {
@@ -250,7 +244,6 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata)
         }
 
         j->written_uncompressed += sz;
-        j->written_since_last_grow += sz;
 
         return 0;
 }
@@ -577,9 +570,6 @@ int pull_job_begin(PullJob *j) {
         if (j->state != PULL_JOB_INIT)
                 return -EBUSY;
 
-        if (j->grow_machine_directory)
-                grow_machine_directory();
-
         r = curl_glue_make(&j->curl, j->url, j);
         if (r < 0)
                 return r;
index 0c104af7589d99edf35ad9c70ef57607bc19d598..c907e74060982a6d554d08d3c89b123f4e9b9f08 100644 (file)
@@ -80,9 +80,6 @@ struct PullJob {
 
         char *checksum;
 
-        bool grow_machine_directory;
-        uint64_t written_since_last_grow;
-
         VerificationStyle style;
 };
 
index 2ceca68c0785c5842ddaa258aba629e86515a588..3a3e015df8faad76c45c92e3740f0b7b2af464d5 100644 (file)
@@ -12,7 +12,6 @@
 #include "copy.h"
 #include "curl-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "hostname-util.h"
 #include "import-common.h"
@@ -27,6 +26,7 @@
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "utf8.h"
 #include "util.h"
 #include "web-util.h"
@@ -56,7 +56,6 @@ struct RawPull {
 
         char *local;
         bool force_local;
-        bool grow_machine_directory;
         bool settings;
         bool roothash;
 
@@ -119,7 +118,6 @@ int raw_pull_new(
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
         _cleanup_(raw_pull_unrefp) RawPull *i = NULL;
         _cleanup_free_ char *root = NULL;
-        bool grow;
         int r;
 
         assert(ret);
@@ -128,8 +126,6 @@ int raw_pull_new(
         if (!root)
                 return -ENOMEM;
 
-        grow = path_startswith(root, "/var/lib/machines");
-
         if (event)
                 e = sd_event_ref(event);
         else {
@@ -150,7 +146,6 @@ int raw_pull_new(
                 .on_finished = on_finished,
                 .userdata = userdata,
                 .image_root = TAKE_PTR(root),
-                .grow_machine_directory = grow,
                 .event = TAKE_PTR(e),
                 .glue = TAKE_PTR(g),
         };
@@ -689,7 +684,6 @@ int raw_pull_start(
         i->raw_job->on_open_disk = raw_pull_job_on_open_disk_raw;
         i->raw_job->on_progress = raw_pull_job_on_progress;
         i->raw_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-        i->raw_job->grow_machine_directory = i->grow_machine_directory;
 
         r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
         if (r < 0)
index 67ea8813e1736e28b8646d69ccef83a1065372c6..e7a208e9048caa671b4dbc4663a633ec55ab436d 100644 (file)
@@ -10,7 +10,6 @@
 #include "copy.h"
 #include "curl-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "hostname-util.h"
 #include "import-common.h"
@@ -25,6 +24,7 @@
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "utf8.h"
 #include "util.h"
 #include "web-util.h"
@@ -52,7 +52,6 @@ struct TarPull {
 
         char *local;
         bool force_local;
-        bool grow_machine_directory;
         bool settings;
 
         pid_t tar_pid;
@@ -112,7 +111,6 @@ int tar_pull_new(
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
         _cleanup_(tar_pull_unrefp) TarPull *i = NULL;
         _cleanup_free_ char *root = NULL;
-        bool grow;
         int r;
 
         assert(ret);
@@ -121,8 +119,6 @@ int tar_pull_new(
         if (!root)
                 return -ENOMEM;
 
-        grow = path_startswith(root, "/var/lib/machines");
-
         if (event)
                 e = sd_event_ref(event);
         else {
@@ -143,7 +139,6 @@ int tar_pull_new(
                 .on_finished = on_finished,
                 .userdata = userdata,
                 .image_root = TAKE_PTR(root),
-                .grow_machine_directory = grow,
                 .event = TAKE_PTR(e),
                 .glue = TAKE_PTR(g),
         };
@@ -512,7 +507,6 @@ int tar_pull_start(
         i->tar_job->on_open_disk = tar_pull_job_on_open_disk_tar;
         i->tar_job->on_progress = tar_pull_job_on_progress;
         i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-        i->tar_job->grow_machine_directory = i->grow_machine_directory;
 
         r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
         if (r < 0)
index 91e25a87ab28b5662612d4a90cf6cd5a596e13e4..4185af63e1908d29a73009d5a8db203b11cf8358 100644 (file)
 #include "hostname-util.h"
 #include "log.h"
 #include "logs-show.h"
+#include "main-func.h"
 #include "microhttpd-util.h"
 #include "os-util.h"
 #include "parse-util.h"
 #include "pretty-print.h"
 #include "sigbus.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define JOURNAL_WAIT_TIMEOUT (10*USEC_PER_SEC)
 static char *arg_key_pem = NULL;
 static char *arg_cert_pem = NULL;
 static char *arg_trust_pem = NULL;
-static char *arg_directory = NULL;
+static const char *arg_directory = NULL;
+
+STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
 
 typedef struct RequestMeta {
         sd_journal *journal;
@@ -980,95 +986,85 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-int main(int argc, char *argv[]) {
-        struct MHD_Daemon *d = NULL;
+static int run(int argc, char *argv[]) {
+        _cleanup_(MHD_stop_daemonp) struct MHD_Daemon *d = NULL;
+        struct MHD_OptionItem opts[] = {
+                { MHD_OPTION_NOTIFY_COMPLETED,
+                  (intptr_t) request_meta_free, NULL },
+                { MHD_OPTION_EXTERNAL_LOGGER,
+                  (intptr_t) microhttpd_logger, NULL },
+                { MHD_OPTION_END, 0, NULL },
+                { MHD_OPTION_END, 0, NULL },
+                { MHD_OPTION_END, 0, NULL },
+                { MHD_OPTION_END, 0, NULL },
+                { MHD_OPTION_END, 0, NULL },
+        };
+        int opts_pos = 2;
+
+        /* We force MHD_USE_ITC here, in order to make sure
+         * libmicrohttpd doesn't use shutdown() on our listening
+         * socket, which would break socket re-activation. See
+         *
+         * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
+         * https://github.com/systemd/systemd/pull/1286
+         */
+
+        int flags =
+                MHD_USE_DEBUG |
+                MHD_USE_DUAL_STACK |
+                MHD_USE_ITC |
+                MHD_USE_POLL_INTERNAL_THREAD |
+                MHD_USE_THREAD_PER_CONNECTION;
         int r, n;
 
         log_setup_service();
 
         r = parse_argv(argc, argv);
-        if (r < 0)
-                return EXIT_FAILURE;
-        if (r == 0)
-                return EXIT_SUCCESS;
+        if (r <= 0)
+                return r;
 
         sigbus_install();
 
         r = setup_gnutls_logger(NULL);
         if (r < 0)
-                return EXIT_FAILURE;
+                return r;
 
         n = sd_listen_fds(1);
-        if (n < 0) {
-                log_error_errno(n, "Failed to determine passed sockets: %m");
-                goto finish;
-        } else if (n > 1) {
-                log_error("Can't listen on more than one socket.");
-                goto finish;
-        } else {
-                struct MHD_OptionItem opts[] = {
-                        { MHD_OPTION_NOTIFY_COMPLETED,
-                          (intptr_t) request_meta_free, NULL },
-                        { MHD_OPTION_EXTERNAL_LOGGER,
-                          (intptr_t) microhttpd_logger, NULL },
-                        { MHD_OPTION_END, 0, NULL },
-                        { MHD_OPTION_END, 0, NULL },
-                        { MHD_OPTION_END, 0, NULL },
-                        { MHD_OPTION_END, 0, NULL },
-                        { MHD_OPTION_END, 0, NULL }};
-                int opts_pos = 2;
-
-                /* We force MHD_USE_ITC here, in order to make sure
-                 * libmicrohttpd doesn't use shutdown() on our listening
-                 * socket, which would break socket re-activation. See
-                 *
-                 * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
-                 * https://github.com/systemd/systemd/pull/1286
-                 */
-
-                int flags =
-                        MHD_USE_DEBUG |
-                        MHD_USE_DUAL_STACK |
-                        MHD_USE_ITC |
-                        MHD_USE_POLL_INTERNAL_THREAD |
-                        MHD_USE_THREAD_PER_CONNECTION;
-
-                if (n > 0)
-                        opts[opts_pos++] = (struct MHD_OptionItem)
-                                {MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START};
-                if (arg_key_pem) {
-                        assert(arg_cert_pem);
-                        opts[opts_pos++] = (struct MHD_OptionItem)
-                                {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_TLS;
-                }
-                if (arg_trust_pem) {
-                        assert(flags & MHD_USE_TLS);
-                        opts[opts_pos++] = (struct MHD_OptionItem)
-                                {MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem};
-                }
-
-                d = MHD_start_daemon(flags, 19531,
-                                     NULL, NULL,
-                                     request_handler, NULL,
-                                     MHD_OPTION_ARRAY, opts,
-                                     MHD_OPTION_END);
+        if (n < 0)
+                return log_error_errno(n, "Failed to determine passed sockets: %m");
+        if (n > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Can't listen on more than one socket.");
+
+        if (n == 1)
+                opts[opts_pos++] = (struct MHD_OptionItem)
+                        { MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START };
+
+        if (arg_key_pem) {
+                assert(arg_cert_pem);
+                opts[opts_pos++] = (struct MHD_OptionItem)
+                        { 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_TLS;
         }
 
-        if (!d) {
-                log_error("Failed to start daemon!");
-                goto finish;
+        if (arg_trust_pem) {
+                assert(flags & MHD_USE_TLS);
+                opts[opts_pos++] = (struct MHD_OptionItem)
+                        { MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem };
         }
 
-        pause();
-
-        r = EXIT_SUCCESS;
+        d = MHD_start_daemon(flags, 19531,
+                             NULL, NULL,
+                             request_handler, NULL,
+                             MHD_OPTION_ARRAY, opts,
+                             MHD_OPTION_END);
+        if (!d)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start daemon!");
 
-finish:
-        if (d)
-                MHD_stop_daemon(d);
+        pause();
 
-        return r;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index c46e0acdd369354d4a20ec64484b1d4e6d2e2614..e1748cb46b8425feb9b12479f5daecfa7b0f1f28 100644 (file)
@@ -6,11 +6,13 @@
 #include "sd-daemon.h"
 
 #include "conf-parser.h"
+#include "daemon-util.h"
 #include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "journal-remote-write.h"
 #include "journal-remote.h"
+#include "main-func.h"
 #include "pretty-print.h"
 #include "process-util.h"
 #include "rlimit-util.h"
 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-remote.pem"
 #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
 
-static char* arg_url = NULL;
-static char* arg_getter = NULL;
-static char* arg_listen_raw = NULL;
-static char* arg_listen_http = NULL;
-static char* arg_listen_https = NULL;
-static char** arg_files = NULL;
+static const char* arg_url = NULL;
+static const char* arg_getter = NULL;
+static const char* arg_listen_raw = NULL;
+static const char* arg_listen_http = NULL;
+static const char* arg_listen_https = NULL;
+static char** arg_files = NULL; /* Do not free this. */
 static int arg_compress = true;
 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_INVALID;
-static char* arg_output = NULL;
+static const char* arg_output = NULL;
 
 static char *arg_key = NULL;
 static char *arg_cert = NULL;
 static char *arg_trust = NULL;
 static bool arg_trust_all = false;
 
+STATIC_DESTRUCTOR_REGISTER(arg_gnutls_log, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_key, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_cert, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_trust, freep);
+
 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
         [JOURNAL_WRITE_SPLIT_NONE] = "none",
         [JOURNAL_WRITE_SPLIT_HOST] = "host",
@@ -81,6 +88,8 @@ static int spawn_child(const char* child, char** argv) {
                         _exit(EXIT_FAILURE);
                 }
 
+                (void) rlimit_nofile_safe();
+
                 execvp(child, argv);
                 log_error_errno(errno, "Failed to exec child %s: %m", child);
                 _exit(EXIT_FAILURE);
@@ -613,8 +622,7 @@ static int create_remoteserver(
         }
 
         if (arg_url) {
-                const char *url;
-                char *hostname;
+                const char *url, *hostname;
 
                 if (!strstr(arg_url, "/entries")) {
                         if (endswith(arg_url, "/"))
@@ -635,7 +643,7 @@ static int create_remoteserver(
 
                 hostname = strndupa(hostname, strcspn(hostname, "/:"));
 
-                r = journal_remote_add_source(s, fd, hostname, false);
+                r = journal_remote_add_source(s, fd, (char *) hostname, false);
                 if (r < 0)
                         return r;
         }
@@ -1059,10 +1067,11 @@ static int load_certificates(char **key, char **cert, char **trust) {
         return 0;
 }
 
-int main(int argc, char **argv) {
-        RemoteServer s = {};
-        int r;
+static int run(int argc, char **argv) {
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
+        _cleanup_(journal_remote_server_destroy) RemoteServer s = {};
         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
+        int r;
 
         log_show_color(true);
         log_parse_environment();
@@ -1072,63 +1081,61 @@ int main(int argc, char **argv) {
 
         r = parse_config();
         if (r < 0)
-                return EXIT_FAILURE;
+                return r;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+                return r;
 
         if (arg_listen_http || arg_listen_https) {
                 r = setup_gnutls_logger(arg_gnutls_log);
                 if (r < 0)
-                        return EXIT_FAILURE;
+                        return r;
         }
 
         if (arg_listen_https || https_socket >= 0) {
-                if (load_certificates(&key, &cert, &trust) < 0)
-                        return EXIT_FAILURE;
+                r = load_certificates(&key, &cert, &trust);
+                if (r < 0)
+                        return r;
+
                 s.check_trust = !arg_trust_all;
         }
 
-        if (create_remoteserver(&s, key, cert, trust) < 0)
-                return EXIT_FAILURE;
+        r = create_remoteserver(&s, key, cert, trust);
+        if (r < 0)
+                return r;
 
         r = sd_event_set_watchdog(s.events, true);
         if (r < 0)
-                log_error_errno(r, "Failed to enable watchdog: %m");
-        else
-                log_debug("Watchdog is %sd.", enable_disable(r > 0));
+                return log_error_errno(r, "Failed to enable watchdog: %m");
+
+        log_debug("Watchdog is %sd.", enable_disable(r > 0));
 
         log_debug("%s running as pid "PID_FMT,
                   program_invocation_short_name, getpid_cached());
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
+
+        notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
 
         while (s.active) {
                 r = sd_event_get_state(s.events);
                 if (r < 0)
-                        break;
+                        return r;
                 if (r == SD_EVENT_FINISHED)
                         break;
 
                 r = sd_event_run(s.events, -1);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to run event loop: %m");
-                        break;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to run event loop: %m");
         }
 
-        sd_notifyf(false,
-                   "STOPPING=1\n"
-                   "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
-        log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
-
-        journal_remote_server_destroy(&s);
+        notify_message = NULL;
+        (void) sd_notifyf(false,
+                          "STOPPING=1\n"
+                          "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
 
-        free(arg_key);
-        free(arg_cert);
-        free(arg_trust);
+        log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
 
-        return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index 1f3cdb932f7593c292817d4134c6751b7ef48380..3c0916c4383236611dc037d77e1f98fa2f865f60 100644 (file)
@@ -346,7 +346,7 @@ static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
 }
 #endif
 
-RemoteServer* journal_remote_server_destroy(RemoteServer *s) {
+void journal_remote_server_destroy(RemoteServer *s) {
         size_t i;
 
 #if HAVE_MICROHTTPD
@@ -370,7 +370,6 @@ RemoteServer* journal_remote_server_destroy(RemoteServer *s) {
                 journal_remote_server_global = NULL;
 
         /* fds that we're listening on remain open... */
-        return NULL;
 }
 
 /**********************************************************************
index e083ea9c74975a208cefad4fd9881f1218463534..4c25d43abf955a6d352fda60aca0d3836dcb6f01 100644 (file)
@@ -62,4 +62,4 @@ int journal_remote_handle_raw_source(
                 uint32_t revents,
                 RemoteServer *s);
 
-RemoteServer* journal_remote_server_destroy(RemoteServer *s);
+void journal_remote_server_destroy(RemoteServer *s);
index 924ea4936e6be35247d9f43268ec28b9e5d5ec00..1e08fcc55415468597086855c8a8bd5e2705d6fd 100644 (file)
 
 #include "alloc-util.h"
 #include "conf-parser.h"
+#include "daemon-util.h"
 #include "def.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
 #include "glob-util.h"
 #include "journal-upload.h"
 #include "log.h"
+#include "main-func.h"
 #include "mkdir.h"
 #include "parse-util.h"
 #include "pretty-print.h"
@@ -26,6 +29,7 @@
 #include "signal-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
@@ -759,10 +763,11 @@ static int open_journal(sd_journal **j) {
         return r;
 }
 
-int main(int argc, char **argv) {
-        Uploader u;
-        int r;
+static int run(int argc, char **argv) {
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
+        _cleanup_(destroy_uploader) Uploader u = {};
         bool use_journal;
+        int r;
 
         log_show_color(true);
         log_parse_environment();
@@ -772,23 +777,23 @@ int main(int argc, char **argv) {
 
         r = parse_config();
         if (r < 0)
-                goto finish;
+                return r;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                goto finish;
+                return r;
 
         sigbus_install();
 
         r = setup_uploader(&u, arg_url, arg_save_state);
         if (r < 0)
-                goto cleanup;
+                return r;
 
         sd_event_set_watchdog(u.events, true);
 
         r = check_cursor_updating(&u);
         if (r < 0)
-                goto cleanup;
+                return r;
 
         log_debug("%s running as pid "PID_FMT,
                   program_invocation_short_name, getpid_cached());
@@ -798,61 +803,51 @@ int main(int argc, char **argv) {
                 sd_journal *j;
                 r = open_journal(&j);
                 if (r < 0)
-                        goto finish;
+                        return r;
                 r = open_journal_for_upload(&u, j,
                                             arg_cursor ?: u.last_cursor,
                                             arg_cursor ? arg_after_cursor : true,
                                             !!arg_follow);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing input...");
+        notify_message = notify_start("READY=1\n"
+                                      "STATUS=Processing input...",
+                                      NOTIFY_STOPPING);
 
         for (;;) {
                 r = sd_event_get_state(u.events);
                 if (r < 0)
-                        break;
+                        return r;
                 if (r == SD_EVENT_FINISHED)
-                        break;
+                        return 0;
 
                 if (use_journal) {
                         if (!u.journal)
-                                break;
+                                return 0;
 
                         r = check_journal_input(&u);
                 } else if (u.input < 0 && !use_journal) {
                         if (optind >= argc)
-                                break;
+                                return 0;
 
                         log_debug("Using %s as input.", argv[optind]);
                         r = open_file_for_upload(&u, argv[optind++]);
                 }
                 if (r < 0)
-                        goto cleanup;
+                        return r;
 
                 if (u.uploading) {
                         r = perform_upload(&u);
                         if (r < 0)
-                                break;
+                                return r;
                 }
 
                 r = sd_event_run(u.events, u.timeout);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to run event loop: %m");
-                        break;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to run event loop: %m");
         }
-
-cleanup:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
-
-        destroy_uploader(&u);
-
-finish:
-        return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index a50a2a75c7fc30ef56f790f7de60306516d7a7c2..364cd0f7cfd2c339e7b9475d96ac8bcc2cf29ed1 100644 (file)
@@ -73,3 +73,5 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn
  * interesting events without overwhelming detail.
  */
 int setup_gnutls_logger(char **categories);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon);
index b30963da667b397467d9f9b58488645f66e5f05f..7b3dc1e9ab0eed9ddf0512c6132a096497f8b01a 100644 (file)
@@ -1,12 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <stdio.h>
-#include <linux/audit.h>
-#if HAVE_AUDIT
-#  include <libaudit.h>
-#endif
-
-#include "missing.h"
 #include "audit-type.h"
+#include "missing_audit.h"
+
 #include "audit_type-to-name.h"
-#include "macro.h"
index 965b044cbf0d3221bdc521c497a17e6cb7460f43..069a883490d69b0b071d3327996bd2caa1a82db9 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <alloca.h>
+#include <stdio.h>
+
 #include "macro.h"
 
 const char *audit_type_to_string(int type);
index 0f18d31addf26afab754fd14bb42ec167fcd1da3..3556a101bf262a3ea29113c57fd4499a86e2c3b4 100644 (file)
@@ -24,6 +24,7 @@
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 const char * const catalog_file_dirs[] = {
@@ -49,9 +50,7 @@ typedef struct CatalogItem {
         le64_t offset;
 } CatalogItem;
 
-static void catalog_hash_func(const void *p, struct siphash *state) {
-        const CatalogItem *i = p;
-
+static void catalog_hash_func(const CatalogItem *i, struct siphash *state) {
         siphash24_compress(&i->id, sizeof(i->id), state);
         siphash24_compress(i->language, strlen(i->language), state);
 }
@@ -69,10 +68,7 @@ static int catalog_compare_func(const CatalogItem *a, const CatalogItem *b) {
         return strcmp(a->language, b->language);
 }
 
-const struct hash_ops catalog_hash_ops = {
-        .hash = catalog_hash_func,
-        .compare = (comparison_fn_t) catalog_compare_func,
-};
+DEFINE_HASH_OPS(catalog_hash_ops, CatalogItem, catalog_hash_func, catalog_compare_func);
 
 static bool next_header(const char **s) {
         const char *e;
index a0621524a9bfcec8fb1f9130d344feaa0a03c17c..87056435fcdd9973237e1f8c230884b4a5057975 100644 (file)
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "io-util.h"
 #include "memfd-util.h"
 #include "socket-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
index 5569ddc31368650f008eee4df508bb9d3b80232b..5eff80a99f01737d9a2b5a1365cb75e1f2f4c0d7 100644 (file)
@@ -17,6 +17,7 @@
 #include "lookup3.h"
 #include "macro.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void draw_progress(uint64_t p, usec_t *last_usec) {
index 4fe6ae7367afb6f96f5ad545cc31a6b6d3485cb6..14a02eda749b4ec9549ab6bd067f16d90fe32d36 100644 (file)
@@ -62,6 +62,7 @@
 #include "strv.h"
 #include "syslog-util.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 
@@ -2110,7 +2111,7 @@ int main(int argc, char *argv[]) {
         case ACTION_UPDATE_CATALOG: {
                 _cleanup_free_ char *database;
 
-                database = path_join(arg_root, CATALOG_DATABASE, NULL);
+                database = path_join(arg_root, CATALOG_DATABASE);
                 if (!database) {
                         r = log_oom();
                         goto finish;
index 7766618c986cd317f491876fe5f7c6e9fa760331..df41f8143553dac28451daa509df393a0bbf9603 100644 (file)
@@ -8,4 +8,4 @@ void server_process_audit_message(Server *s, const void *buffer, size_t buffer_s
 
 void process_audit_string(Server *s, int type, const char *data, size_t size);
 
-int server_open_audit(Server*s);
+int server_open_audit(Server *s);
index 7a43599329ec0bfc8aed9204b931139fa07fb83d..e86178ed775a038935d6d54a895d5eaa4ed8329b 100644 (file)
@@ -433,7 +433,7 @@ void server_process_native_file(
         }
 }
 
-int server_open_native_socket(Server*s) {
+int server_open_native_socket(Server *s) {
 
         static const union sockaddr_union sa = {
                 .un.sun_family = AF_UNIX,
index ebe49850f53f6c7dfdfd9dfacec49fd71c42d8ba..137c8f04469d63683361c7557155ffd0fa7df6ff 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "alloc-util.h"
 #include "dirent-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -31,6 +32,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "syslog-util.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 
 #define STDOUT_STREAMS_MAX 4096
index ff194dd95176c472458e0c61c3cc29ec5ac36aa8..6c61f17c7db80fe895556c6eb44993b43fd6e89e 100644 (file)
@@ -319,7 +319,7 @@ uint32_t jenkins_hashlittle( const void *key, size_t length, uint32_t initval)
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !HAS_FEATURE_ADDRESS_SANITIZER
 
     switch(length)
     {
@@ -504,7 +504,7 @@ void jenkins_hashlittle2(
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !HAS_FEATURE_ADDRESS_SANITIZER
 
     switch(length)
     {
@@ -680,7 +680,7 @@ uint32_t jenkins_hashbig( const void *key, size_t length, uint32_t initval)
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !HAS_FEATURE_ADDRESS_SANITIZER
 
     switch(length)
     {
index 807dece545c96dffcab9186674741d39be40aea4..e03d6dc232713a35da9e60216e46d9514149f417 100644 (file)
@@ -34,7 +34,7 @@ endif
 ############################################################
 
 audit_type_includes = [config_h,
-                       missing_h,
+                       missing_audit_h,
                        'linux/audit.h']
 if conf.get('HAVE_AUDIT') == 1
         audit_type_includes += 'libaudit.h'
index 952f67a0d90a6e97838ac9408ccdafe8d117600b..b5ff5b64f33352f644f7cce3ff4e4eb4831614ed 100644 (file)
@@ -16,6 +16,7 @@
 #include "catalog.h"
 #include "compress.h"
 #include "dirent-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
index e9a751bdfd75ddd307f13ed3d6f4e32b822ce396..192bb0cb07e0bac67847069f21870ebd0dd87659 100644 (file)
 #include "catalog.h"
 #include "fd-util.h"
 #include "fs-util.h"
-#include "fileio.h"
 #include "log.h"
 #include "macro.h"
 #include "path-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static char** catalog_dirs = NULL;
index bf35a5f4b937b282ab182dd3437edd67fd42465f..1b050b70523d4f74cb89e9a32a7061c137275567 100644 (file)
@@ -7,12 +7,12 @@
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "path-util.h"
 #include "random-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #if HAVE_XZ
index f74b49d5010cde0e94c444246215e5d27ec83841..8e839920b9b2245f8e3611ca3808300693ea0d3f 100644 (file)
@@ -11,7 +11,7 @@
 
 int main(int argc, char *argv[]) {
         unsigned n = 0;
-        _cleanup_(sd_journal_closep) sd_journal*j = NULL;
+        _cleanup_(sd_journal_closep) sd_journal *j = NULL;
 
         test_setup_logging(LOG_DEBUG);
 
index 897364201cfde36dd24e3c0341bf103ea4590c70..b17527916cff62f623cd6580135ae5dbddcc010d 100644 (file)
@@ -12,7 +12,7 @@
 #include "util.h"
 
 int main(int argc, char *argv[]) {
-        _cleanup_(sd_journal_closep) sd_journal*j = NULL;
+        _cleanup_(sd_journal_closep) sd_journal *j = NULL;
         _cleanup_free_ char *t;
 
         test_setup_logging(LOG_DEBUG);
index 5c55b35f57912b75f4dd4b541762199c29d3aecf..8f755efdde27f5f98e48f6ffd7af86ec1d3c4561 100644 (file)
@@ -6,9 +6,9 @@
 #include <unistd.h>
 
 #include "fd-util.h"
-#include "fileio.h"
 #include "macro.h"
 #include "mmap-cache.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
index 6355128ddb27c28387d21cf0105c0862aa0a7d1b..8a7c5bc28f2a37a6d8131809fdf983a5a47a5ccf 100644 (file)
@@ -78,5 +78,5 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
                             DHCPRequest *req, DHCPPacket *packet,
                             int type, size_t optoffset);
 
-void client_id_hash_func(const void *p, struct siphash *state);
-int client_id_compare_func(const void *_a, const void *_b);
+void client_id_hash_func(const DHCPClientId *p, struct siphash *state);
+int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b);
index f3c4e0ac881a1dd78fc4d080e736409f6dc40474..952197e714930992c292e2fa7a732b87bd116aac 100644 (file)
@@ -7,11 +7,10 @@
 #include "in-addr-util.h"
 #include "lldp-internal.h"
 #include "lldp-neighbor.h"
+#include "missing.h"
 #include "unaligned.h"
 
-static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
-        const LLDPNeighborID *id = p;
-
+static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
         siphash24_compress(id->chassis_id, id->chassis_id_size, state);
         siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
         siphash24_compress(id->port_id, id->port_id_size, state);
@@ -36,10 +35,8 @@ int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID
         return CMP(x->port_id_size, y->port_id_size);
 }
 
-const struct hash_ops lldp_neighbor_id_hash_ops = {
-        .hash = lldp_neighbor_id_hash_func,
-        .compare = (__compar_fn_t) lldp_neighbor_id_compare_func,
-};
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func,
+                                      sd_lldp_neighbor, lldp_neighbor_unlink);
 
 int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
         const sd_lldp_neighbor *x = a, *y = b;
index 2241c3bd9df201a0fdd454f33d61e1f45bf25b16..62dbff42cad1f89d5ce792c2f559236a39c56171 100644 (file)
@@ -80,7 +80,7 @@ static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
         return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
 }
 
-extern const struct hash_ops lldp_neighbor_id_hash_ops;
+extern const struct hash_ops lldp_neighbor_hash_ops;
 int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
 int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
 
index a4020d1e19d51351024310cd0f6940e6de47c991..870584c0db872bbbd385f285bb2be40332a7aa64 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "fd-util.h"
 #include "lldp-network.h"
+#include "missing.h"
 #include "socket-util.h"
 
 int lldp_network_bind_raw_socket(int ifindex) {
index b982dcc07df82604f3716a2322db57016b037568..6935311b9a9f3f0302fbcef53f8a85fbfe2106a0 100644 (file)
@@ -676,7 +676,7 @@ _public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret)
                                 _cleanup_free_ char *normalized = NULL;
 
                                 e[n] = 0;
-                                r = dns_name_normalize(e, &normalized);
+                                r = dns_name_normalize(e, 0, &normalized);
                                 if (r < 0)
                                         return r;
 
index c2455c7133b54494938c9acc6cb56b8077be8f3b..13badbf0bfb1ce642c583642e8287baa5b7fe6e4 100644 (file)
@@ -16,6 +16,7 @@
 #include "dhcp-lease-internal.h"
 #include "dhcp-protocol.h"
 #include "dns-domain.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "hexdecoct.h"
@@ -26,6 +27,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "unaligned.h"
 
 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -353,7 +355,7 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
                 return 0;
         }
 
-        r = dns_name_normalize(name, &normalized);
+        r = dns_name_normalize(name, 0, &normalized);
         if (r < 0)
                 return r;
 
index 2a68a029859bbeded3d7cd2369bf5345670d7fcf..7cb44d1fdfa3da5dc7ceefb7930d91809ddb54d3 100644 (file)
 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
 
-static void dhcp_lease_free(DHCPLease *lease) {
+static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
         if (!lease)
-                return;
+                return NULL;
 
         free(lease->client_id.data);
-        free(lease);
+        return mfree(lease);
 }
 
 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
@@ -90,7 +90,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
                         server->bound_leases[server_off - offset] = &server->invalid_lease;
 
                 /* Drop any leases associated with the old address range */
-                hashmap_clear_with_destructor(server->leases_by_client_id, dhcp_lease_free);
+                hashmap_clear(server->leases_by_client_id);
         }
 
         return 0;
@@ -102,9 +102,7 @@ int sd_dhcp_server_is_running(sd_dhcp_server *server) {
         return !!server->receive_message;
 }
 
-void client_id_hash_func(const void *p, struct siphash *state) {
-        const DHCPClientId *id = p;
-
+void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
         assert(id);
         assert(id->length);
         assert(id->data);
@@ -113,13 +111,9 @@ void client_id_hash_func(const void *p, struct siphash *state) {
         siphash24_compress(id->data, id->length, state);
 }
 
-int client_id_compare_func(const void *_a, const void *_b) {
-        const DHCPClientId *a, *b;
+int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
         int r;
 
-        a = _a;
-        b = _b;
-
         assert(!a->length || a->data);
         assert(!b->length || b->data);
 
@@ -130,14 +124,10 @@ int client_id_compare_func(const void *_a, const void *_b) {
         return memcmp(a->data, b->data, a->length);
 }
 
-static const struct hash_ops client_id_hash_ops = {
-        .hash = client_id_hash_func,
-        .compare = client_id_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func,
+                                              DHCPLease, dhcp_lease_free);
 
 static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
-        DHCPLease *lease;
-
         assert(server);
 
         log_dhcp_server(server, "UNREF");
@@ -150,8 +140,6 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
         free(server->dns);
         free(server->ntp);
 
-        while ((lease = hashmap_steal_first(server->leases_by_client_id)))
-                dhcp_lease_free(lease);
         hashmap_free(server->leases_by_client_id);
 
         free(server->bound_leases);
@@ -177,7 +165,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
         server->netmask = htobe32(INADDR_ANY);
         server->ifindex = ifindex;
 
-        server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
+        server->leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops);
         if (!server->leases_by_client_id)
                 return -ENOMEM;
 
index 4e3ee53cd716c49412b870b09c218b582ff20dfd..969fc71051bcead68d4eed3096e30381fa9a6869 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <arpa/inet.h>
 #include <linux/sockios.h>
+#include <sys/ioctl.h>
 
 #include "sd-lldp.h"
 
@@ -27,12 +28,9 @@ static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event);
 
 static void lldp_flush_neighbors(sd_lldp *lldp) {
-        sd_lldp_neighbor *n;
-
         assert(lldp);
 
-        while ((n = hashmap_first(lldp->neighbor_by_id)))
-                lldp_neighbor_unlink(n);
+        hashmap_clear(lldp->neighbor_by_id);
 }
 
 static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
@@ -375,7 +373,7 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
                 .capability_mask = (uint16_t) -1,
         };
 
-        lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
+        lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops);
         if (!lldp->neighbor_by_id)
                 return -ENOMEM;
 
index fe458bcaa625d3dfd086054ea518324aff804888..098e01fb82527356c6fb5bfecccc1a47cea06353 100644 (file)
@@ -503,6 +503,10 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
         if (!p)
                 return -EINVAL;
 
+        /* Refuse prefixes that don't have a prefix set */
+        if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr))
+                return -ENOEXEC;
+
         LIST_FOREACH(prefix, cur, ra->prefixes) {
 
                 r = in_addr_prefix_intersect(AF_INET6,
index d88b018dc9432d073e22ca397875f7bb89e31469..fa94b3cb7529bb632aaa1947e1cf35e63a90069f 100644 (file)
@@ -20,6 +20,7 @@
 #include "macro.h"
 #include "socket-util.h"
 #include "tests.h"
+#include "util.h"
 #include "virt.h"
 
 static struct ether_addr mac_addr = {
index 071691327b712e615bac86df8ade0a6384bcf9b0..f441bb6972ea1e86a563d2b4ec64a4474df26bcf 100644 (file)
@@ -8,7 +8,7 @@ id128_sources = files('''
 
 sd_daemon_c = files('sd-daemon/sd-daemon.c')
 
-sd_event_c = files('''
+sd_event_sources = files('''
         sd-event/event-source.h
         sd-event/event-util.c
         sd-event/event-util.h
@@ -90,7 +90,7 @@ libsystemd_sources = files('''
         sd-path/sd-path.c
         sd-resolve/sd-resolve.c
         sd-utf8/sd-utf8.c
-'''.split()) + id128_sources + sd_daemon_c + sd_event_c + sd_login_c
+'''.split()) + id128_sources + sd_daemon_c + sd_event_sources + sd_login_c
 
 disable_mempool_c = files('disable-mempool.c')
 
index 2787e8505ba404c5b0d6c0cdffdc73400d121d66..7775d2b376253edae1ffcd061b45e96f989e2018 100644 (file)
@@ -430,7 +430,7 @@ _public_ int sd_bus_get_name_creds(
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
-        const char *unique = NULL;
+        const char *unique;
         pid_t pid = 0;
         int r;
 
@@ -459,9 +459,12 @@ _public_ int sd_bus_get_name_creds(
         if (!BUS_IS_OPEN(bus->state))
                 return -ENOTCONN;
 
-        /* Only query the owner if the caller wants to know it or if
-         * the caller just wants to check whether a name exists */
-        if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
+        /* If the name is unique anyway, we can use it directly */
+        unique = name[0] == ':' ? name : NULL;
+
+        /* Only query the owner if the caller wants to know it and the name is not unique anyway, or if the caller just
+         * wants to check whether a name exists */
+        if ((FLAGS_SET(mask, SD_BUS_CREDS_UNIQUE_NAME) && !unique) || mask == 0) {
                 r = sd_bus_call_method(
                                 bus,
                                 "org.freedesktop.DBus",
@@ -483,6 +486,7 @@ _public_ int sd_bus_get_name_creds(
         if (mask != 0) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 bool need_pid, need_uid, need_selinux, need_separate_calls;
+
                 c = bus_creds_new();
                 if (!c)
                         return -ENOMEM;
@@ -661,7 +665,7 @@ _public_ int sd_bus_get_name_creds(
                                                 NULL,
                                                 &reply,
                                                 "s",
-                                                unique ? unique : name);
+                                                unique ?: name);
                                 if (r < 0)
                                         return r;
 
@@ -688,7 +692,7 @@ _public_ int sd_bus_get_name_creds(
                                                 &error,
                                                 &reply,
                                                 "s",
-                                                unique ? unique : name);
+                                                unique ?: name);
                                 if (r < 0) {
                                         if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
                                                 return r;
@@ -699,7 +703,7 @@ _public_ int sd_bus_get_name_creds(
                                         if (r < 0)
                                                 return r;
 
-                                        c->label = strndup(p, sz);
+                                        c->label = memdup_suffix0(p, sz);
                                         if (!c->label)
                                                 return -ENOMEM;
 
index 506ed0d73c3303444258796b490217f7e7c032d6..38900cf718be84051211bd2ab2d37980b3085f17 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/time.h>
+
 #include "alloc-util.h"
 #include "bus-dump.h"
 #include "bus-internal.h"
index 5ef643134eabfcb167c42651982c2d2e1c222a8a..dc952375b6853729eccd3b3acdf606a242e53524 100644 (file)
@@ -54,8 +54,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
 };
 
 /* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
-extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
-extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[];
 
 /* Additional maps registered with sd_bus_error_add_map() are in this
  * NULL terminated array */
@@ -89,9 +89,8 @@ static int bus_error_name_to_errno(const char *name) {
                                         return m->code;
                         }
 
-        m = __start_BUS_ERROR_MAP;
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-        while (m < __stop_BUS_ERROR_MAP) {
+        m = ALIGN_TO_PTR(__start_SYSTEMD_BUS_ERROR_MAP, sizeof(void*));
+        while (m < __stop_SYSTEMD_BUS_ERROR_MAP) {
                 /* For magic ELF error maps, the end marker might
                  * appear in the middle of things, since multiple maps
                  * might appear in the same section. Hence, let's skip
@@ -99,7 +98,7 @@ static int bus_error_name_to_errno(const char *name) {
                  * boundary, which is the selected alignment for the
                  * arrays. */
                 if (m->code == BUS_ERROR_MAP_END_MARKER) {
-                        m = ALIGN8_PTR(m+1);
+                        m = ALIGN_TO_PTR(m + 1, sizeof(void*));
                         continue;
                 }
 
@@ -108,7 +107,6 @@ static int bus_error_name_to_errno(const char *name) {
 
                 m++;
         }
-#endif
 
         return EIO;
 }
index e8e743c0d75a378325a342219dc4badcd48ddc75..a6523e57a2767a6e6b6770cab3bbd683422382d0 100644 (file)
@@ -31,13 +31,14 @@ int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_lis
  */
 
 #define BUS_ERROR_MAP_ELF_REGISTER                                      \
-        __attribute__ ((__section__("BUS_ERROR_MAP")))                  \
-        __attribute__ ((__used__))                                      \
-        __attribute__ ((__aligned__(8)))
+        _section_("SYSTEMD_BUS_ERROR_MAP")                              \
+        _used_                                                          \
+        _alignptr_                                                      \
+        _variable_no_sanitize_address_
 
 #define BUS_ERROR_MAP_ELF_USE(errors)                                   \
         extern const sd_bus_error_map errors[];                         \
-        __attribute__ ((__used__))                                      \
+        _used_                                                          \
         static const sd_bus_error_map * const CONCATENATE(errors ## _copy_, __COUNTER__) = errors;
 
 /* We use something exotic as end marker, to ensure people build the
index 1310cf91e5dc36bc0ee26332964f9bc1833ed202..40acae2133814dd0b639c15667f9b64cf457d681 100644 (file)
@@ -151,26 +151,6 @@ bool service_name_is_valid(const char *p) {
         return true;
 }
 
-char* service_name_startswith(const char *a, const char *b) {
-        const char *p;
-
-        if (!service_name_is_valid(a) ||
-            !service_name_is_valid(b))
-                return NULL;
-
-        p = startswith(a, b);
-        if (!p)
-                return NULL;
-
-        if (*p == 0)
-                return (char*) p;
-
-        if (*p == '.')
-                return (char*) p + 1;
-
-        return NULL;
-}
-
 bool member_name_is_valid(const char *p) {
         const char *q;
 
index 4bc945d9eea39be571dc4eaba45a39224be9efd4..b352f0bfe5e054344d5d5c0818592e6e6644364a 100644 (file)
@@ -305,8 +305,6 @@ struct sd_bus {
         sd_bus **default_bus_ptr;
         pid_t tid;
 
-        char *cgroup_root;
-
         char *description;
         char *patch_sender;
 
@@ -346,7 +344,6 @@ struct sd_bus {
 
 bool interface_name_is_valid(const char *p) _pure_;
 bool service_name_is_valid(const char *p) _pure_;
-char* service_name_startswith(const char *a, const char *b);
 bool member_name_is_valid(const char *p) _pure_;
 bool object_path_is_valid(const char *p) _pure_;
 char *object_path_startswith(const char *a, const char *b) _pure_;
@@ -397,8 +394,6 @@ int bus_set_address_user(sd_bus *bus);
 int bus_set_address_system_remote(sd_bus *b, const char *host);
 int bus_set_address_system_machine(sd_bus *b, const char *machine);
 
-int bus_get_root_path(sd_bus *bus);
-
 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
 
 #define bus_assert_return(expr, r, error)                               \
index 37b851b94ce37b61056ba70be4ac51861e871482..6812c28904acbe0acea321c2e7599ddad42a4c42 100644 (file)
@@ -542,43 +542,6 @@ fail:
         return r;
 }
 
-static int bus_match_find_compare_value(
-                struct bus_match_node *where,
-                enum bus_match_node_type t,
-                uint8_t value_u8,
-                const char *value_str,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *c, *n;
-
-        assert(where);
-        assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
-        assert(BUS_MATCH_IS_COMPARE(t));
-        assert(ret);
-
-        for (c = where->child; c && c->type != t; c = c->next)
-                ;
-
-        if (!c)
-                return 0;
-
-        if (t == BUS_MATCH_MESSAGE_TYPE)
-                n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
-        else if (BUS_MATCH_CAN_HASH(t))
-                n = hashmap_get(c->compare.children, value_str);
-        else {
-                for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
-                        ;
-        }
-
-        if (n) {
-                *ret = n;
-                return 1;
-        }
-
-        return 0;
-}
-
 static int bus_match_add_leaf(
                 struct bus_match_node *where,
                 struct match_callback *callback) {
@@ -607,34 +570,6 @@ static int bus_match_add_leaf(
         return 1;
 }
 
-static int bus_match_find_leaf(
-                struct bus_match_node *where,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *c;
-
-        assert(where);
-        assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
-        assert(ret);
-
-        for (c = where->child; c; c = c->next) {
-                sd_bus_slot *s;
-
-                s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
-
-                if (c->type == BUS_MATCH_LEAF &&
-                    c->leaf.callback->callback == callback &&
-                    s->userdata == userdata) {
-                        *ret = c;
-                        return 1;
-                }
-        }
-
-        return 0;
-}
-
 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
         assert(k);
 
@@ -1014,43 +949,6 @@ int bus_match_remove(
         return 1;
 }
 
-int bus_match_find(
-                struct bus_match_node *root,
-                struct bus_match_component *components,
-                unsigned n_components,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                struct match_callback **ret) {
-
-        struct bus_match_node *n, **gc;
-        unsigned i;
-        int r;
-
-        assert(root);
-        assert(ret);
-
-        gc = newa(struct bus_match_node*, n_components);
-
-        n = root;
-        for (i = 0; i < n_components; i++) {
-                r = bus_match_find_compare_value(
-                                n, components[i].type,
-                                components[i].value_u8, components[i].value_str,
-                                &n);
-                if (r <= 0)
-                        return r;
-
-                gc[i] = n;
-        }
-
-        r = bus_match_find_leaf(n, callback, userdata, &n);
-        if (r <= 0)
-                return r;
-
-        *ret = n->leaf.callback;
-        return 1;
-}
-
 void bus_match_free(struct bus_match_node *node) {
         struct bus_match_node *c;
 
index b9c0fcec9069de2c88c2762ad8a73fa80b749ea7..a6f67ce089740fdae8615c0b4a2b1c11e8bcb642 100644 (file)
@@ -66,8 +66,6 @@ int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
 int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, struct match_callback *callback);
 int bus_match_remove(struct bus_match_node *root, struct match_callback *callback);
 
-int bus_match_find(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, struct match_callback **ret);
-
 void bus_match_free(struct bus_match_node *node);
 
 void bus_match_dump(struct bus_match_node *node, unsigned level);
index f25db359981c4ce3c42f5a8bc56835add839938b..bb7e09c945ab7b7c18e578fdbc7e033691a2a025 100644 (file)
@@ -5829,16 +5829,6 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
         return 0;
 }
 
-int bus_message_append_sender(sd_bus_message *m, const char *sender) {
-        assert(m);
-        assert(sender);
-
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->sender, -EPERM);
-
-        return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
-}
-
 _public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
         assert_return(m, -EINVAL);
         assert_return(priority, -EINVAL);
index ef6ddc1cc0aaa9619e7f3991f0911252d3f2869a..0115437d26b3b8b109f1948199ccf6829bb95c82 100644 (file)
@@ -209,7 +209,5 @@ int bus_message_new_synthetic_error(sd_bus *bus, uint64_t serial, const sd_bus_e
 
 int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
 
-int bus_message_append_sender(sd_bus_message *m, const char *sender);
-
 void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m);
 void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m);
index 03c8e56ef876f09af81bee3ed8e2c97cc5220006..d0538104ae251100f2e1ffd1f366040d646d6bfc 100644 (file)
@@ -9,6 +9,7 @@
 #include "bus-slot.h"
 #include "bus-type.h"
 #include "bus-util.h"
+#include "missing_capability.h"
 #include "set.h"
 #include "string-util.h"
 #include "strv.h"
@@ -1582,9 +1583,7 @@ _public_ int sd_bus_add_fallback(
         return bus_add_object(bus, slot, true, prefix, callback, userdata);
 }
 
-static void vtable_member_hash_func(const void *a, struct siphash *state) {
-        const struct vtable_member *m = a;
-
+static void vtable_member_hash_func(const struct vtable_member *m, struct siphash *state) {
         assert(m);
 
         string_hash_func(m->path, state);
@@ -1592,8 +1591,7 @@ static void vtable_member_hash_func(const void *a, struct siphash *state) {
         string_hash_func(m->member, state);
 }
 
-static int vtable_member_compare_func(const void *a, const void *b) {
-        const struct vtable_member *x = a, *y = b;
+static int vtable_member_compare_func(const struct vtable_member *x, const struct vtable_member *y) {
         int r;
 
         assert(x);
@@ -1610,10 +1608,7 @@ static int vtable_member_compare_func(const void *a, const void *b) {
         return strcmp(x->member, y->member);
 }
 
-static const struct hash_ops vtable_member_hash_ops = {
-        .hash = vtable_member_hash_func,
-        .compare = vtable_member_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(vtable_member_hash_ops, struct vtable_member, vtable_member_hash_func, vtable_member_compare_func);
 
 static int add_object_vtable_internal(
                 sd_bus *bus,
index f7485211ac60ec15c6eedef4c1dba6246fe75424..ed185131b83ae40215398b0453191cc67b2db2b4 100644 (file)
@@ -21,6 +21,7 @@
 #include "missing.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
 #include "stdio-util.h"
@@ -932,6 +933,8 @@ int bus_socket_exec(sd_bus *b) {
                 if (rearrange_stdio(s[1], s[1], STDERR_FILENO) < 0)
                         _exit(EXIT_FAILURE);
 
+                (void) rlimit_nofile_safe();
+
                 if (b->exec_argv)
                         execvp(b->exec_path, b->exec_argv);
                 else {
index 4c959cc29ccfbe88cb10f3c30f3678ae7a75ed22..efbd3ed5f016e9a53bd2c3a855c6513cb2a963e8 100644 (file)
@@ -50,6 +50,8 @@ static struct track_item* track_item_free(struct track_item *i) {
 }
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free);
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(track_item_hash_ops, char, string_hash_func, string_compare_func,
+                                              struct track_item, track_item_free);
 
 static void bus_track_add_to_queue(sd_bus_track *track) {
         assert(track);
@@ -150,7 +152,7 @@ static sd_bus_track *track_free(sd_bus_track *track) {
                 LIST_REMOVE(tracks, track->bus->tracks, track);
 
         bus_track_remove_from_queue(track);
-        track->names = hashmap_free_with_destructor(track->names, track_item_free);
+        track->names = hashmap_free(track->names);
         track->bus = sd_bus_unref(track->bus);
 
         if (track->destroy_callback)
@@ -201,7 +203,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
                 return 0;
         }
 
-        r = hashmap_ensure_allocated(&track->names, &string_hash_ops);
+        r = hashmap_ensure_allocated(&track->names, &track_item_hash_ops);
         if (r < 0)
                 return r;
 
@@ -397,7 +399,7 @@ void bus_track_close(sd_bus_track *track) {
                 return;
 
         /* Let's flush out all names */
-        hashmap_clear_with_destructor(track->names, track_item_free);
+        hashmap_clear(track->names);
 
         /* Invoke handler */
         if (track->handler)
index 63eed99d282d27dc161f029bc7a5923f53370708..18564a53834a1d71ade295c0ef901dabc3d65cfb 100644 (file)
@@ -30,32 +30,6 @@ bool bus_type_is_valid(char c) {
         return !!memchr(valid, c, sizeof(valid));
 }
 
-bool bus_type_is_valid_in_signature(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_BYTE,
-                SD_BUS_TYPE_BOOLEAN,
-                SD_BUS_TYPE_INT16,
-                SD_BUS_TYPE_UINT16,
-                SD_BUS_TYPE_INT32,
-                SD_BUS_TYPE_UINT32,
-                SD_BUS_TYPE_INT64,
-                SD_BUS_TYPE_UINT64,
-                SD_BUS_TYPE_DOUBLE,
-                SD_BUS_TYPE_STRING,
-                SD_BUS_TYPE_OBJECT_PATH,
-                SD_BUS_TYPE_SIGNATURE,
-                SD_BUS_TYPE_ARRAY,
-                SD_BUS_TYPE_VARIANT,
-                SD_BUS_TYPE_STRUCT_BEGIN,
-                SD_BUS_TYPE_STRUCT_END,
-                SD_BUS_TYPE_DICT_ENTRY_BEGIN,
-                SD_BUS_TYPE_DICT_ENTRY_END,
-                SD_BUS_TYPE_UNIX_FD
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
 bool bus_type_is_basic(char c) {
         static const char valid[] = {
                 SD_BUS_TYPE_BYTE,
index b518461b16f9165c54fbf2b184835559b3ab123a..0ecd8513fd252c12d182e73f1cbede75bf672d3f 100644 (file)
@@ -6,7 +6,6 @@
 #include "macro.h"
 
 bool bus_type_is_valid(char c) _const_;
-bool bus_type_is_valid_in_signature(char c) _const_;
 bool bus_type_is_basic(char c) _const_;
 /* "trivial" is systemd's term for what the D-Bus Specification calls
  * a "fixed type": that is, a basic type of fixed length */
index f086d13898f285a94b1c3e4073c678eec0e3ff1e..3b00bc815725dbc607b86f3e1d7fdf28e3f98669 100644 (file)
@@ -194,7 +194,6 @@ static sd_bus* bus_free(sd_bus *b) {
         free(b->auth_buffer);
         free(b->address);
         free(b->machine);
-        free(b->cgroup_root);
         free(b->description);
         free(b->patch_sender);
 
@@ -3929,24 +3928,6 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
         return 0;
 }
 
-int bus_get_root_path(sd_bus *bus) {
-        int r;
-
-        if (bus->cgroup_root)
-                return 0;
-
-        r = cg_get_root_path(&bus->cgroup_root);
-        if (r == -ENOENT) {
-                bus->cgroup_root = strdup("/");
-                if (!bus->cgroup_root)
-                        return -ENOMEM;
-
-                r = 0;
-        }
-
-        return r;
-}
-
 _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
         assert_return(bus, -EINVAL);
         assert_return(bus = bus_resolve(bus), -ENOPKG);
index 92624909e00132245fe84aab2f25bd8357ee8b0c..2dd3d41a302a290b6c9409e26ce1292909d3ac2d 100644 (file)
@@ -10,6 +10,7 @@
 #include "bus-util.h"
 #include "def.h"
 #include "fd-util.h"
+#include "missing_resource.h"
 #include "time-util.h"
 #include "util.h"
 
index 2ba6eaee7d17871deccad944dfb95a13289fabdf..6181fb163e1f64399b29e158b1e22fe96244eb73 100644 (file)
@@ -245,7 +245,7 @@ fail:
         return r;
 }
 
-static void* client1(void*p) {
+static void* client1(void *p) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -344,7 +344,7 @@ static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_er
         return 1;
 }
 
-static void* client2(void*p) {
+static void* client2(void *p) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
index 8f1fc54520597eafe9818f2082f5df96017e92fa..f464b5b23de42b7715489957e60ad932b6925f56 100644 (file)
@@ -113,18 +113,18 @@ static void test_error(void) {
         assert_se(!sd_bus_error_is_set(&error));
 }
 
-extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
-extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[];
 
 static void dump_mapping_table(void) {
         const sd_bus_error_map *m;
 
         printf("----- errno mappings ------\n");
-        m = __start_BUS_ERROR_MAP;
-        while (m < __stop_BUS_ERROR_MAP) {
+        m = ALIGN_TO_PTR(__start_SYSTEMD_BUS_ERROR_MAP, sizeof(void*));
+        while (m < __stop_SYSTEMD_BUS_ERROR_MAP) {
 
                 if (m->code == BUS_ERROR_MAP_END_MARKER) {
-                        m = ALIGN8_PTR(m+1);
+                        m = ALIGN_TO_PTR(m + 1, sizeof(void*));
                         continue;
                 }
 
index d1c674b223afcdcf587d5234ab69d25c9214ceac..1e9810ce4fb13b1ea14a52870552188530c7e7ea 100644 (file)
@@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
         log_info("message size = %zu, contents =\n%s", sz, h);
 
 #if HAVE_GLIB
-#ifndef __SANITIZE_ADDRESS__
+#if !HAS_FEATURE_ADDRESS_SANITIZER
         {
                 GDBusMessage *g;
                 char *p;
index 40879b85375a623ce8e522822724024f65a09d35..4b3da30079764cf66ea5500b120a74530e0cf6b1 100644 (file)
@@ -8,7 +8,6 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "mkdir.h"
 #include "path-util.h"
@@ -16,6 +15,7 @@
 #include "rm-rf.h"
 #include "socket-util.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 
 static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         log_info("Got Foobar() call.");
index 3ab3ce0dca1a6d6d90c57bd5c012c8539229a731..fcf9b761ee9fb6e20085ee6c9ab52934faaa64cd 100644 (file)
@@ -18,7 +18,7 @@
 #include "hashmap.h"
 #include "io-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "set.h"
 #include "socket-util.h"
 #include "string-util.h"
index 8cc216c353985eacbf811738ee1bfb692a0f25ff..95a581e66efdcb12481bdb54bb344c059b8124a5 100644 (file)
@@ -24,6 +24,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "strxcpyx.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index dc75f91e21cda5983a6b7b3d015c8d7e723187e8..d5583488f20ce828fb430ba20ab77b60b22aecef 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <ctype.h>
 #include <net/if.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 
 #include "sd-device.h"
@@ -594,16 +595,17 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
 
         switch (id[0]) {
         case 'b':
-        case 'c':
-        {
-                char type;
-                int maj, min;
+        case 'c': {
+                dev_t devt;
 
-                r = sscanf(id, "%c%i:%i", &type, &maj, &min);
-                if (r != 3)
+                if (isempty(id))
                         return -EINVAL;
 
-                return sd_device_new_from_devnum(ret, type, makedev(maj, min));
+                r = parse_dev(id + 1, &devt);
+                if (r < 0)
+                        return r;
+
+                return sd_device_new_from_devnum(ret, id[0], devt);
         }
         case 'n':
         {
index f0c58a589af3674c95ad95586bae9552a7d89a5f..0030ea5dbe88aa7b3a9f8191ed2a53b964f0a723 100644 (file)
@@ -1371,8 +1371,7 @@ static int event_make_inotify_data(
         return 1;
 }
 
-static int inode_data_compare(const void *a, const void *b) {
-        const struct inode_data *x = a, *y = b;
+static int inode_data_compare(const struct inode_data *x, const struct inode_data *y) {
         int r;
 
         assert(x);
@@ -1385,19 +1384,14 @@ static int inode_data_compare(const void *a, const void *b) {
         return CMP(x->ino, y->ino);
 }
 
-static void inode_data_hash_func(const void *p, struct siphash *state) {
-        const struct inode_data *d = p;
-
-        assert(p);
+static void inode_data_hash_func(const struct inode_data *d, struct siphash *state) {
+        assert(d);
 
         siphash24_compress(&d->dev, sizeof(d->dev), state);
         siphash24_compress(&d->ino, sizeof(d->ino), state);
 }
 
-const struct hash_ops inode_data_hash_ops = {
-        .hash = inode_data_hash_func,
-        .compare = inode_data_compare
-};
+DEFINE_PRIVATE_HASH_OPS(inode_data_hash_ops, struct inode_data, inode_data_hash_func, inode_data_compare);
 
 static void event_free_inode_data(
                 sd_event *e,
index 50074a56be81fa9f974eb6c8312252691e9135e0..6fd6d9f0b041fb81005e5a61cfd93a9e9b45712c 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "log.h"
 #include "macro.h"
@@ -17,6 +16,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static int prepare_handler(sd_event_source *s, void *userdata) {
index 87259daadc78b9a6a98929ee9b1e01d51ce3c33b..c5c329f2ac6c7538172a7541059188cff40b70db 100644 (file)
@@ -16,6 +16,7 @@
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 
 static const char *default_hwdb_bin_dir = "/etc/udev";
 static const char * const conf_file_dirs[] = {
index 95c9e1138ceb8ca1bc4782afebd8fb419694ffb0..9ffd594ee661ded38d6609d28b9bbbd12f419446 100644 (file)
@@ -182,15 +182,12 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
         return id128_write_fd(fd, f, id, do_sync);
 }
 
-void id128_hash_func(const void *p, struct siphash *state) {
-        siphash24_compress(p, 16, state);
+void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
+        siphash24_compress(p, sizeof(sd_id128_t), state);
 }
 
-int id128_compare_func(const void *a, const void *b) {
+int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
         return memcmp(a, b, 16);
 }
 
-const struct hash_ops id128_hash_ops = {
-        .hash = id128_hash_func,
-        .compare = id128_compare_func,
-};
+DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
index 44f159c0b6269502b73f9a29c026265f9f94a9e6..65f14ab2527ae4209ed9815b910687a52350aa03 100644 (file)
@@ -28,6 +28,6 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
 int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
 int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
 
-void id128_hash_func(const void *p, struct siphash *state);
-int id128_compare_func(const void *a, const void *b) _pure_;
+void id128_hash_func(const sd_id128_t *p, struct siphash *state);
+int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
 extern const struct hash_ops id128_hash_ops;
index e048d2ce185305294f39c6e71debfc1c7f5ee9a9..a904c6b544410bcbff294add89ee0807f802a430 100644 (file)
@@ -11,9 +11,9 @@
 #include "alloc-util.h"
 #include "cgroup-util.h"
 #include "dirent-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "hostname-util.h"
index 823e654d11fad23c6d1bbca0a27279952b655fda..64ab386df3f1c0a7378a62254976c79f0a34bc3e 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/fou.h>
 #endif
 
-#if HAVE_VXCAN_INFO_PEER
+#if HAVE_LINUX_CAN_VXCAN_H
 #include <linux/can/vxcan.h>
 #endif
 
@@ -412,17 +412,40 @@ static const NLTypeSystem rtnl_link_info_type_system = {
 };
 
 static const struct NLType rtnl_prot_info_bridge_port_types[] = {
-        [IFLA_BRPORT_STATE]             = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_COST]              = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BRPORT_PRIORITY]          = { .type = NETLINK_TYPE_U16 },
-        [IFLA_BRPORT_MODE]              = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_GUARD]             = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_PROTECT]           = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_FAST_LEAVE]        = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_LEARNING]          = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_UNICAST_FLOOD]     = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_PROXYARP]          = { .type = NETLINK_TYPE_U8 },
-        [IFLA_BRPORT_LEARNING_SYNC]     = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_STATE]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_COST]                = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BRPORT_PRIORITY]            = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_MODE]                = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_GUARD]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_PROTECT]             = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_FAST_LEAVE]          = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_LEARNING]            = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_UNICAST_FLOOD]       = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_PROXYARP]            = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_LEARNING_SYNC]       = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_PROXYARP_WIFI]       = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_ROOT_ID]             = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_BRIDGE_ID]           = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_DESIGNATED_PORT]     = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_DESIGNATED_COST]     = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_ID]                  = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_NO]                  = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_TOPOLOGY_CHANGE_ACK] = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_CONFIG_PENDING]      = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_MESSAGE_AGE_TIMER]   = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BRPORT_FORWARD_DELAY_TIMER] = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BRPORT_HOLD_TIMER]          = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BRPORT_FLUSH]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_MULTICAST_ROUTER]    = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_PAD]                 = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_MCAST_FLOOD]         = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_MCAST_TO_UCAST]      = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_VLAN_TUNNEL]         = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_BCAST_FLOOD]         = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_GROUP_FWD_MASK]      = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BRPORT_NEIGH_SUPPRESS]      = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_ISOLATED]            = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BRPORT_BACKUP_PORT]         = { .type = NETLINK_TYPE_U32 },
 };
 
 static const NLTypeSystem rtnl_prot_info_type_systems[] = {
index b326ceecafa3db3611d05cc6bf524a06b03410db..d2723285a681a3695eee67fff3c6c570d352cf7b 100644 (file)
@@ -38,3 +38,23 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
 
 int rtnl_log_parse_error(int r);
 int rtnl_log_create_error(int r);
+
+#define netlink_call_async(nl, ret_slot, message, callback, destroy_callback, userdata) \
+        ({                                                              \
+                int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \
+                void (*_destroy_)(typeof(userdata)) = destroy_callback; \
+                sd_netlink_call_async(nl, ret_slot, message,            \
+                                      (sd_netlink_message_handler_t) _callback_, \
+                                      (sd_netlink_destroy_t) _destroy_, \
+                                      userdata, 0, __func__);           \
+        })
+
+#define netlink_add_match(nl, ret_slot, metch, callback, destroy_callback, userdata) \
+        ({                                                              \
+                int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \
+                void (*_destroy_)(typeof(userdata)) = destroy_callback; \
+                sd_netlink_add_match(nl, ret_slot, match,               \
+                                     (sd_netlink_message_handler_t) _callback_, \
+                                     (sd_netlink_destroy_t) _destroy_,  \
+                                     userdata, __func__);               \
+        })
index 4416e1720cb2e65a48a464a1aa93f0497130a978..2d4d00e0eb128571b191f0c1629be9685c4ba215 100644 (file)
@@ -852,6 +852,32 @@ int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, unsigne
         return 0;
 }
 
+int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags) {
+        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_flags |= flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, unsigned *flags) {
+        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);
+        *flags = routing_policy_rule->rtm_flags;
+
+        return 0;
+}
+
 int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type) {
         struct rtmsg *routing_policy_rule;
 
index fc66d41b638ac8f3da72d9366c5918701ce3d513..4b66a92203ada24c4bf3a4eb09ef07c61ab943f5 100644 (file)
@@ -8,8 +8,8 @@
 #include "sd-network.h"
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "parse-util.h"
index 77481002106f673a06583df12d31158beedc3381..bff2c4976b9e5d4b171c60b0ac9a18a20e97cb68 100644 (file)
@@ -14,6 +14,7 @@
 #include "macro.h"
 #include "socket-util.h"
 #include "string-util.h"
+#include "time-util.h"
 
 #define TEST_TIMEOUT_USEC (20*USEC_PER_SEC)
 
index 0bf62df22e1322849b7e557cd6d7616ca872cfe0..6b6b32a5910cdd4d504f47a36492ddf0cbcd9fc9 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "bus-util.h"
 #include "def.h"
+#include "env-file.h"
+#include "env-file-label.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio-label.h"
@@ -17,6 +19,7 @@
 #include "mkdir.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 
 static bool startswith_comma(const char *s, const char *prefix) {
         s = startswith(s, prefix);
index 34065a98c754d4825502945b761401147e65de9a..69f5667801d0b63f92227213907867ae0852f170 100644 (file)
@@ -505,7 +505,7 @@ static int localectl_main(sd_bus *bus, int argc, char *argv[]) {
         return dispatch_verb(argc, argv, verbs, bus);
 }
 
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
index 79a6d3e4d022708934822b345ca38476a26ad0e2..f851d35a08e412868cc447d0a7812975538bb0aa 100644 (file)
@@ -20,6 +20,7 @@
 #include "locale-util.h"
 #include "macro.h"
 #include "main-func.h"
+#include "missing_capability.h"
 #include "path-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
index 2394c5d937eb4a171dd9061e651779acacbcdfdf..f574d429f49f8d0e1d87d331859dddc5d5391816 100644 (file)
@@ -83,7 +83,7 @@ static int print_inhibitors(sd_bus *bus) {
         if (r < 0)
                 return log_error_errno(r, "Could not get active inhibitors: %s", bus_error_message(&error, r));
 
-        table = table_new("WHO", "UID", "USER", "PID", "COMM", "WHAT", "WHY", "MODE");
+        table = table_new("who", "uid", "user", "pid", "comm", "what", "why", "mode");
         if (!table)
                 return log_oom();
 
@@ -303,7 +303,7 @@ static int run(int argc, char *argv[]) {
                 if (fd < 0)
                         return log_error_errno(fd, "Failed to inhibit: %s", bus_error_message(&error, fd));
 
-                r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
+                r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
                 if (r < 0)
                         return r;
                 if (r == 0) {
index fb5240d7d368c2c95e0bd32974ef6b572f36ace2..ab1b56201a37be0f0be339721ddb95c26ce8932e 100644 (file)
@@ -101,7 +101,10 @@ static int show_table(Table *table, const char *word) {
 
                 table_set_header(table, arg_legend);
 
-                r = table_print(table, NULL);
+                if (OUTPUT_MODE_IS_JSON(arg_output))
+                        r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
+                else
+                        r = table_print(table, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to show table: %m");
         }
@@ -143,7 +146,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("SESSION", "UID", "USER", "SEAT", "TTY");
+        table = table_new("session", "uid", "user", "seat", "tty");
         if (!table)
                 return log_oom();
 
@@ -224,7 +227,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("UID", "USER");
+        table = table_new("uid", "user");
         if (!table)
                 return log_oom();
 
@@ -281,7 +284,7 @@ static int list_seats(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("SEAT");
+        table = table_new("seat");
         if (!table)
                 return log_oom();
 
@@ -1434,6 +1437,10 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_output < 0)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Unknown output '%s'.", optarg);
+
+                        if (OUTPUT_MODE_IS_JSON(arg_output))
+                                arg_legend = false;
+
                         break;
 
                 case ARG_NO_PAGER:
index 7c9cf05dd7d8c151538ec63737644d68206f6723..daffbf0668cd397af469146e2a0ab388a69213f0 100644 (file)
@@ -12,6 +12,7 @@
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "logind-button.h"
+#include "missing_input.h"
 #include "string-util.h"
 #include "util.h"
 
index 740cf0b7865cfcf32a510688f57fe7d43428054f..d009851cf44b6eb6cd18e8c9c4eafa6c59f01038 100644 (file)
@@ -20,7 +20,7 @@ struct Button {
 };
 
 Button* button_new(Manager *m, const char *name);
-void button_free(Button*b);
+void button_free(Button *b);
 int button_open(Button *b);
 int button_set_seat(Button *b, const char *sn);
 int button_check_switches(Button *b);
index ab4561a555d6690b3deab69e948ea884d33d5502..766a9236be17a46e71a0e6ea47ac6ee0f0ca9a63 100644 (file)
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio-label.h"
+#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "logind.h"
+#include "missing_capability.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -32,6 +34,7 @@
 #include "special.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 #include "utmp-wtmp.h"
index 71eea72da59fe8101e7532272fff80d7b473c032..415c26b147de6cfa3c7504a4d674684a332bc6dd 100644 (file)
@@ -6,6 +6,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -15,6 +16,7 @@
 #include "parse-util.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index 8002901cf793334d7aae0c79107878785e30cc31..6ee5a1c95d27ce94ee30c1a85a1ee1cd3a83af2f 100644 (file)
@@ -9,6 +9,7 @@
 #include "bus-util.h"
 #include "logind-seat.h"
 #include "logind.h"
+#include "missing_capability.h"
 #include "strv.h"
 #include "user-util.h"
 #include "util.h"
index 3b06169c1de2bde15139641a18dd499dbdebee8b..c758ffd5fad0a0130de29cf880b923274af3820b 100644 (file)
@@ -19,6 +19,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 int seat_new(Seat** ret, Manager *m, const char *id) {
index 5b09a07ffacbc472aaae231cc4e3c462607cf9c6..df5bfba98213bd9f601fec8c5d60a256cc5de945 100644 (file)
@@ -11,7 +11,9 @@
 #include "logind-session-device.h"
 #include "logind-session.h"
 #include "logind.h"
+#include "missing_capability.h"
 #include "signal-util.h"
+#include "stat-util.h"
 #include "strv.h"
 #include "util.h"
 
@@ -380,6 +382,9 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er
         if (r < 0)
                 return r;
 
+        if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
@@ -427,6 +432,9 @@ static int method_release_device(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 return r;
 
+        if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
@@ -455,6 +463,9 @@ static int method_pause_device_complete(sd_bus_message *message, void *userdata,
         if (r < 0)
                 return r;
 
+        if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
index 576a17a7f031dd58d9bdb938f7ba3ccf9eda6e7a..4b4dd4c060bed5710a58c5f0409ce1cfbca09102 100644 (file)
@@ -16,6 +16,7 @@
 #include "audit-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -30,6 +31,7 @@
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index 9620fb0cfc2344c247531d5ff8f98e1bc96c5918..fcaeba13f6b2c20c5e6248415cef82e40d1ec7bd 100644 (file)
@@ -8,6 +8,7 @@
 #include "format-util.h"
 #include "logind-user.h"
 #include "logind.h"
+#include "missing_capability.h"
 #include "signal-util.h"
 #include "strv.h"
 #include "user-util.h"
index 8d8294461876241e5d4917b3efe2e60c6e68eb49..ae27bfb6622fde83d28b90dde085796850cdf5f4 100644 (file)
@@ -11,6 +11,7 @@
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "clean-ipc.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -28,6 +29,7 @@
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 #include "util.h"
index 75c9303ff3c5dd03d172cb415de6e96cc104dd0a..a891b0af6fbbb2e4c4f8fd8450e982ffcbe0b66b 100644 (file)
@@ -65,7 +65,7 @@ static void print_inhibitors(sd_bus *bus) {
         printf("%u inhibitors\n", n);
 }
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
         int fd1, fd2;
         int r;
index edb62a2d30d78ed3939080f77afb736f44ba08e6..5e58e4baadbf1f02a937d8159adb9ec9de5c8b2f 100644 (file)
@@ -10,7 +10,7 @@
 #include "label.h"
 #include "main-func.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "selinux-util.h"
index 89df274544cbe939def4e7c427442d975cd02741..7e7f0d51bfb0db5ea8a2adaf82b9d626788a6442 100644 (file)
@@ -15,6 +15,7 @@
 #include "io-util.h"
 #include "loop-util.h"
 #include "machine-image.h"
+#include "missing_capability.h"
 #include "mount-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
@@ -169,7 +170,7 @@ int bus_image_method_clone(
         if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
                 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
 
-        r = safe_fork("(imgclone)", FORK_RESET_SIGNALS, &child);
+        r = safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
         if (r == 0) {
@@ -382,7 +383,7 @@ static int image_flush_cache(sd_event_source *s, void *userdata) {
         assert(s);
         assert(m);
 
-        hashmap_clear_with_destructor(m->image_cache, image_unref);
+        hashmap_clear(m->image_cache);
         return 0;
 }
 
@@ -412,7 +413,7 @@ int image_object_find(sd_bus *bus, const char *path, const char *interface, void
                 return 1;
         }
 
-        r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
+        r = hashmap_ensure_allocated(&m->image_cache, &image_hash_ops);
         if (r < 0)
                 return r;
 
@@ -461,7 +462,7 @@ char *image_bus_path(const char *name) {
 }
 
 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        _cleanup_hashmap_free_ Hashmap *images = NULL;
         _cleanup_strv_free_ char **l = NULL;
         Image *image;
         Iterator i;
@@ -471,7 +472,7 @@ int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char **
         assert(path);
         assert(nodes);
 
-        images = hashmap_new(&string_hash_ops);
+        images = hashmap_new(&image_hash_ops);
         if (!images)
                 return -ENOMEM;
 
index da861c536cdb8ed84904ffe958d5e42c8133a3ee..285918b4cc5c63f9badd98718a8371924e953ac9 100644 (file)
@@ -17,9 +17,9 @@
 #include "bus-label.h"
 #include "bus-util.h"
 #include "copy.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "in-addr-util.h"
@@ -27,6 +27,7 @@
 #include "local-addresses.h"
 #include "machine-dbus.h"
 #include "machine.h"
+#include "missing_capability.h"
 #include "mkdir.h"
 #include "os-util.h"
 #include "path-util.h"
@@ -34,6 +35,7 @@
 #include "signal-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
index e114541b3f0c078daed9584f401d6483094bc390..6af12765f5dcb08fe085f18983440c5beaffed5d 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "env-file.h"
 #include "escape.h"
 #include "extract-word.h"
 #include "fd-util.h"
@@ -26,6 +27,7 @@
 #include "stdio-util.h"
 #include "string-table.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 #include "util.h"
@@ -70,8 +72,9 @@ fail:
         return mfree(m);
 }
 
-void machine_free(Machine *m) {
-        assert(m);
+Machine* machine_free(Machine *m) {
+        if (!m)
+                return NULL;
 
         while (m->operations)
                 operation_free(m->operations);
@@ -98,7 +101,7 @@ void machine_free(Machine *m) {
         free(m->service);
         free(m->root_directory);
         free(m->netif);
-        free(m);
+        return mfree(m);
 }
 
 int machine_save(Machine *m) {
index 967c11039b77be69ce324459d2982ecaa2a11fd2..31527d029b27acf8757a7dd1c1106b7db0011780 100644 (file)
@@ -65,7 +65,7 @@ struct Machine {
 };
 
 Machine* machine_new(Manager *manager, MachineClass class, const char *name);
-void machine_free(Machine *m);
+Machine* machine_free(Machine *m);
 bool machine_may_gc(Machine *m, bool drop_not_started);
 void machine_add_to_gc_queue(Machine *m);
 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error);
index 094ee9d360e508f7133241e69ec3b69dd7c689de..12b8d69cbd05992c5d7637f2d109099826b43c27 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <locale.h>
+#include <math.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <string.h>
@@ -258,7 +259,10 @@ static int show_table(Table *table, const char *word) {
 
                 table_set_header(table, arg_legend);
 
-                r = table_print(table, NULL);
+                if (OUTPUT_MODE_IS_JSON(arg_output))
+                        r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
+                else
+                        r = table_print(table, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to show table: %m");
         }
@@ -296,7 +300,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
 
-        table = table_new("MACHINE", "CLASS", "SERVICE", "OS", "VERSION", "ADDRESSES");
+        table = table_new("machine", "class", "service", "os", "version", "addresses");
         if (!table)
                 return log_oom();
 
@@ -331,7 +335,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
                                 name,
                                 0,
                                 "",
-                                "",
+                                " ",
                                 arg_addrs,
                                 &addresses);
 
@@ -376,7 +380,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
 
-        table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED");
+        table = table_new("name", "type", "ro", "usage", "created", "modified");
         if (!table)
                 return log_oom();
 
@@ -474,20 +478,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         return 0;
 }
 
-static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2, int n_addr) {
-        _cleanup_free_ char *s = NULL;
-        int r;
-
-        r = call_get_addresses(bus, name, ifi, prefix, prefix2, n_addr, &s);
-        if (r < 0)
-                return r;
-
-        if (r > 0)
-                fputs(s, stdout);
-
-        return r;
-}
-
 static int print_os_release(sd_bus *bus, const char *method, const char *name, const char *prefix) {
         _cleanup_free_ char *pretty = NULL;
         int r;
@@ -560,6 +550,7 @@ static void machine_status_info_clear(MachineStatusInfo *info) {
 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
         char since2[FORMAT_TIMESTAMP_MAX];
+        _cleanup_free_ char *addresses = NULL;
         const char *s1, *s2;
         int ifi = -1;
 
@@ -629,11 +620,12 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
                 fputc('\n', stdout);
         }
 
-        if (print_addresses(bus, i->name, ifi,
-                            "\t Address: ",
-                            "\n\t          ",
-                            ALL_IP_ADDRESSES) > 0)
+        if (call_get_addresses(bus, i->name, ifi,
+                               "\t Address: ", "\n\t          ", ALL_IP_ADDRESSES,
+                               &addresses) > 0) {
+                fputs(addresses, stdout);
                 fputc('\n', stdout);
+        }
 
         print_os_release(bus, "GetMachineOSRelease", i->name, "\t      OS: ");
 
@@ -1999,28 +1991,38 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
         return -r;
 }
 
+static const char *nullify_dash(const char *p) {
+        if (isempty(p))
+                return NULL;
+
+        if (streq(p, "-"))
+                return NULL;
+
+        return p;
+}
+
 static int import_tar(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_free_ char *ll = NULL;
-        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
+        _cleanup_close_ int fd = -1;
         sd_bus *bus = userdata;
         int r;
 
         assert(bus);
 
         if (argc >= 2)
-                path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+                path = nullify_dash(argv[1]);
 
         if (argc >= 3)
-                local = argv[2];
-        else if (path)
-                local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
 
+                local = fn;
+        }
         if (!local) {
                 log_error("Need either path or local name.");
                 return -EINVAL;
@@ -2068,26 +2070,26 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
 static int import_raw(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_free_ char *ll = NULL;
-        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
+        _cleanup_close_ int fd = -1;
         sd_bus *bus = userdata;
         int r;
 
         assert(bus);
 
         if (argc >= 2)
-                path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+                path = nullify_dash(argv[1]);
 
         if (argc >= 3)
-                local = argv[2];
-        else if (path)
-                local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
 
+                local = fn;
+        }
         if (!local) {
                 log_error("Need either path or local name.");
                 return -EINVAL;
@@ -2133,6 +2135,67 @@ static int import_raw(int argc, char *argv[], void *userdata) {
         return transfer_image_common(bus, m);
 }
 
+static int import_fs(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        const char *local = NULL, *path = NULL;
+        _cleanup_free_ char *fn = NULL;
+        _cleanup_close_ int fd = -1;
+        sd_bus *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        if (argc >= 2)
+                path = nullify_dash(argv[1]);
+
+        if (argc >= 3)
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
+
+                local = fn;
+        }
+        if (!local) {
+                log_error("Need either path or local name.");
+                return -EINVAL;
+        }
+
+        if (!machine_name_is_valid(local)) {
+                log_error("Local name %s is not a suitable machine name.", local);
+                return -EINVAL;
+        }
+
+        if (path) {
+                fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open directory '%s': %m", path);
+        }
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        &m,
+                        "org.freedesktop.import1",
+                        "/org/freedesktop/import1",
+                        "org.freedesktop.import1.Manager",
+                        "ImportFileSystem");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(
+                        m,
+                        "hsbb",
+                        fd >= 0 ? fd : STDIN_FILENO,
+                        local,
+                        arg_force,
+                        arg_read_only);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return transfer_image_common(bus, m);
+}
+
 static void determine_compression_from_filename(const char *p) {
         if (arg_format)
                 return;
@@ -2464,12 +2527,21 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
                        (int) max_remote, "REMOTE");
 
         for (j = 0; j < n_transfers; j++)
-                printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
-                       (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
-                       (int) 6, (unsigned) (transfers[j].progress * 100),
-                       (int) max_type, transfers[j].type,
-                       (int) max_local, transfers[j].local,
-                       (int) max_remote, transfers[j].remote);
+
+                if (transfers[j].progress < 0)
+                        printf("%*" PRIu32 " %*s %-*s %-*s %-*s\n",
+                               (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
+                               (int) 7, "n/a",
+                               (int) max_type, transfers[j].type,
+                               (int) max_local, transfers[j].local,
+                               (int) max_remote, transfers[j].remote);
+                else
+                        printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
+                               (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
+                               (int) 6, (unsigned) (transfers[j].progress * 100),
+                               (int) max_type, transfers[j].type,
+                               (int) max_local, transfers[j].local,
+                               (int) max_remote, transfers[j].remote);
 
         if (arg_legend) {
                 if (n_transfers > 0)
@@ -2687,6 +2759,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"
                "  import-tar FILE [NAME]      Import a local TAR container image\n"
                "  import-raw FILE [NAME]      Import a local RAW container or VM image\n"
+               "  import-fs DIRECTORY [NAME]  Import a local directory container image\n"
                "  export-tar NAME [FILE]      Export a TAR container image locally\n"
                "  export-raw NAME [FILE]      Export a RAW container or VM image locally\n"
                "  list-transfers              Show list of downloads in progress\n"
@@ -2851,6 +2924,9 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_output < 0)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Unknown output '%s'.", optarg);
+
+                        if (OUTPUT_MODE_IS_JSON(arg_output))
+                                arg_legend = false;
                         break;
 
                 case ARG_NO_PAGER:
@@ -3008,6 +3084,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
                 { "disable",         2,        VERB_ANY, 0,            enable_machine    },
                 { "import-tar",      2,        3,        0,            import_tar        },
                 { "import-raw",      2,        3,        0,            import_raw        },
+                { "import-fs",       2,        3,        0,            import_fs         },
                 { "export-tar",      2,        3,        0,            export_tar        },
                 { "export-raw",      2,        3,        0,            export_raw        },
                 { "pull-tar",        2,        3,        0,            pull_tar          },
@@ -3022,7 +3099,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
         return dispatch_verb(argc, argv, verbs, bus);
 }
 
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
index 87e6298c7810f50e352c1ef58efe53f609e56f96..d613414fded43b55efb3b0b6d842c2a6f1add0e5 100644 (file)
 #include "machine-image.h"
 #include "machine-pool.h"
 #include "machined.h"
+#include "missing_capability.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "stdio-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 
@@ -41,15 +43,10 @@ static int property_get_pool_usage(
 
         _cleanup_close_ int fd = -1;
         uint64_t usage = (uint64_t) -1;
-        struct stat st;
 
         assert(bus);
         assert(reply);
 
-        /* We try to read the quota info from /var/lib/machines, as
-         * well as the usage of the loopback file
-         * /var/lib/machines.raw, and pick the larger value. */
-
         fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
         if (fd >= 0) {
                 BtrfsQuotaInfo q;
@@ -58,11 +55,6 @@ static int property_get_pool_usage(
                         usage = q.referenced;
         }
 
-        if (stat("/var/lib/machines.raw", &st) >= 0) {
-                if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
-                        usage = st.st_blocks * 512ULL;
-        }
-
         return sd_bus_message_append(reply, "t", usage);
 }
 
@@ -77,15 +69,10 @@ static int property_get_pool_limit(
 
         _cleanup_close_ int fd = -1;
         uint64_t size = (uint64_t) -1;
-        struct stat st;
 
         assert(bus);
         assert(reply);
 
-        /* We try to read the quota limit from /var/lib/machines, as
-         * well as the size of the loopback file
-         * /var/lib/machines.raw, and pick the smaller value. */
-
         fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
         if (fd >= 0) {
                 BtrfsQuotaInfo q;
@@ -94,11 +81,6 @@ static int property_get_pool_limit(
                         size = q.referenced_max;
         }
 
-        if (stat("/var/lib/machines.raw", &st) >= 0) {
-                if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
-                        size = st.st_size;
-        }
-
         return sd_bus_message_append(reply, "t", size);
 }
 
@@ -483,7 +465,7 @@ static int method_get_machine_os_release(sd_bus_message *message, void *userdata
 
 static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        _cleanup_hashmap_free_ Hashmap *images = NULL;
         Manager *m = userdata;
         Image *image;
         Iterator i;
@@ -492,7 +474,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
         assert(message);
         assert(m);
 
-        images = hashmap_new(&string_hash_ops);
+        images = hashmap_new(&image_hash_ops);
         if (!images)
                 return -ENOMEM;
 
@@ -760,7 +742,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
         if (r == 0) {
-                _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+                _cleanup_hashmap_free_ Hashmap *images = NULL;
                 bool success = true;
                 Image *image;
                 Iterator i;
@@ -768,7 +750,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
 
                 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
 
-                images = hashmap_new(&string_hash_ops);
+                images = hashmap_new(&image_hash_ops);
                 if (!images) {
                         r = -ENOMEM;
                         goto child_fail;
@@ -877,19 +859,10 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
                 return 1; /* Will call us back */
 
         /* Set up the machine directory if necessary */
-        r = setup_machine_directory(limit, error);
+        r = setup_machine_directory(error);
         if (r < 0)
                 return r;
 
-        /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
-        if (limit != (uint64_t) -1) {
-                r = btrfs_resize_loopback("/var/lib/machines", limit, false);
-                if (r == -ENOTTY)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
-                if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
-                        return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
-        }
-
         (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
 
         r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
index 22eb030dee6afb40fd69a9392fb5413fd7d29038..dec2164bb04eda4f37b56153edf6ab92f984fc73 100644 (file)
@@ -25,6 +25,9 @@
 static Manager* manager_unref(Manager *m);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(machine_hash_ops, void, trivial_hash_func, trivial_compare_func,
+                                              Machine, machine_free);
+
 static int manager_new(Manager **ret) {
         _cleanup_(manager_unrefp) Manager *m = NULL;
         int r;
@@ -37,7 +40,7 @@ static int manager_new(Manager **ret) {
 
         m->machines = hashmap_new(&string_hash_ops);
         m->machine_units = hashmap_new(&string_hash_ops);
-        m->machine_leaders = hashmap_new(NULL);
+        m->machine_leaders = hashmap_new(&machine_hash_ops);
 
         if (!m->machines || !m->machine_units || !m->machine_leaders)
                 return -ENOMEM;
@@ -61,8 +64,6 @@ static int manager_new(Manager **ret) {
 }
 
 static Manager* manager_unref(Manager *m) {
-        Machine *machine;
-
         if (!m)
                 return NULL;
 
@@ -71,14 +72,10 @@ static Manager* manager_unref(Manager *m) {
 
         assert(m->n_operations == 0);
 
-        while ((machine = hashmap_first(m->machines)))
-                machine_free(machine);
-
         hashmap_free(m->machines);
         hashmap_free(m->machine_units);
         hashmap_free(m->machine_leaders);
-
-        hashmap_free_with_destructor(m->image_cache, image_unref);
+        hashmap_free(m->image_cache);
 
         sd_event_source_unref(m->image_cache_defer_event);
 
index 4d53bc5597b0044628694d1a933f63beb3bfd1c9..bbbc91c38e3ed4ed1f07fdee851e4c872da32f01 100644 (file)
@@ -17,6 +17,7 @@
 #include "fstab-util.h"
 #include "main-func.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
index 207d67874f00c110901ed5ebf4fe5fc51e27cc80..37f7cf8ccdbbc6dd30030ed014b022df541cb9ec 100644 (file)
@@ -1,10 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "fuzz.h"
 #include "networkd-manager.h"
+#include "tmpfile-util.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(manager_freep) Manager *manager = NULL;
index 078b1e6d93c230087b834d66b3269d4735bcea62..4b795008055d47ec9b3cdb53b879c026f3d0fb68 100644 (file)
@@ -1,10 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "fuzz.h"
 #include "networkd-manager.h"
+#include "tmpfile-util.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(manager_freep) Manager *manager = NULL;
index d4fa27a288ff5a8919b24521b0a666eece26e8a2..8fe4854424b8cd08ff77b4acccf6ba43b185fffb 100644 (file)
@@ -64,6 +64,8 @@ sources = files('''
         networkd-manager.h
         networkd-ndisc.c
         networkd-ndisc.h
+        networkd-neighbor.c
+        networkd-neighbor.h
         networkd-radv.c
         networkd-radv.h
         networkd-network-bus.c
index cb00780b8a08b85133408d3530f5abd04b925400..0c804adb2ef92d77e2b6de9dca27263d73265dad 100644 (file)
@@ -9,8 +9,7 @@
 #include "vlan-util.h"
 
 /* callback for brige netdev's parameter set */
-static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        NetDev *netdev = userdata;
+static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
         int r;
 
         assert(netdev);
@@ -129,8 +128,8 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
-        r = sd_netlink_call_async(netdev->manager->rtnl, NULL, req, netdev_bridge_set_handler,
-                                  netdev_destroy_callback, netdev, 0, __func__);
+        r = netlink_call_async(netdev->manager->rtnl, NULL, req, netdev_bridge_set_handler,
+                               netdev_destroy_callback, netdev);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
index 9e4c1e962939e6b6f75041cd1c66a456637a8e72..b8abed19bd9160085e4507e11b3d2b6fd0855751 100644 (file)
@@ -6,7 +6,7 @@
 #endif
 
 #include "in-addr-util.h"
-#include "missing.h"
+#include "missing_fou.h"
 #include "netdev/netdev.h"
 
 typedef enum FooOverUDPEncapType {
index 1742e399b8953cf7c691b2595e41e19256276e9f..089bbfea22443b80871a0113c2ade8a02d9398f9 100644 (file)
@@ -2,12 +2,14 @@
 
 #include <net/if.h>
 
+#include "sd-netlink.h"
+
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "extract-word.h"
 #include "geneve.h"
+#include "netlink-util.h"
 #include "parse-util.h"
-#include "sd-netlink.h"
 #include "string-util.h"
 #include "strv.h"
 #include "missing.h"
@@ -17,8 +19,7 @@
 #define DEFAULT_GENEVE_DESTINATION_PORT 6081
 
 /* callback for geneve netdev's created without a backing Link */
-static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        NetDev *netdev = userdata;
+static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
         int r;
 
         assert(netdev);
@@ -136,8 +137,8 @@ static int netdev_geneve_create(NetDev *netdev) {
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-        r = sd_netlink_call_async(netdev->manager->rtnl, NULL, m, geneve_netdev_create_handler,
-                                  netdev_destroy_callback, netdev, 0, __func__);
+        r = netlink_call_async(netdev->manager->rtnl, NULL, m, geneve_netdev_create_handler,
+                               netdev_destroy_callback, netdev);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
index b60587f2b6f3c6bf69f7fbd9d3368bda719a721b..fb426d37e5d814a4eedb5b8a4b89d138d514d879 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/if_link.h>
 
-#include "missing.h"
+#include "missing_if_link.h"
 #include "netdev/netdev.h"
 
 typedef enum IPVlanMode {
index 49752c2d8a2e96bcd57dc61573c37b08aee636ae..fbc7a59e9e8ca3749947b14ff0fd8be20d63b232 100644 (file)
@@ -73,6 +73,7 @@ Tunnel.Encapsulation,              config_parse_fou_encap_type,          0,
 Tunnel.IPv6RapidDeploymentPrefix,  config_parse_6rd_prefix,              0,                             0
 Tunnel.ERSPANIndex,                config_parse_uint32,                  0,                             offsetof(Tunnel, erspan_index)
 Tunnel.SerializeTunneledPackets,   config_parse_tristate,                0,                             offsetof(Tunnel, erspan_sequence)
+Tunnel.ISATAP,                     config_parse_tristate,                0,                             offsetof(Tunnel, isatap)
 FooOverUDP.Protocol,               config_parse_uint8,                   0,                             offsetof(FouTunnel, fou_protocol)
 FooOverUDP.Encapsulation,          config_parse_fou_encap_type,          0,                             offsetof(FouTunnel, fou_encap_type)
 FooOverUDP.Port,                   config_parse_ip_port,                 0,                             offsetof(FouTunnel, port)
index c3cebe450cb456ab0fef8eddba32a51ddb02e00c..f0e9d002468b8b7ddd858e0a839e2666b21854bb 100644 (file)
@@ -191,14 +191,6 @@ static NetDev *netdev_free(NetDev *netdev) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
 
-void netdev_destroy_callback(void *userdata) {
-        NetDev *netdev = userdata;
-
-        assert(userdata);
-
-        netdev_unref(netdev);
-}
-
 void netdev_drop(NetDev *netdev) {
         if (!netdev || netdev->state == NETDEV_STATE_LINGER)
                 return;
@@ -242,7 +234,7 @@ static int netdev_enter_failed(NetDev *netdev) {
         return 0;
 }
 
-static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message_handler_t callback) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -269,8 +261,8 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
 
-        r = sd_netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
@@ -314,8 +306,7 @@ static int netdev_enter_ready(NetDev *netdev) {
 }
 
 /* callback for netdev's created without a backing Link */
-static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        NetDev *netdev = userdata;
+static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
         int r;
 
         assert(netdev);
@@ -336,7 +327,7 @@ static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
         return 1;
 }
 
-static int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -512,8 +503,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
         return 0;
 }
 
-static int netdev_create(NetDev *netdev, Link *link,
-                         sd_netlink_message_handler_t callback) {
+static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -580,15 +570,15 @@ static int netdev_create(NetDev *netdev, Link *link,
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
                 if (link) {
-                        r = sd_netlink_call_async(netdev->manager->rtnl, NULL, m, callback,
-                                                  link_netlink_destroy_callback, link, 0, __func__);
+                        r = netlink_call_async(netdev->manager->rtnl, NULL, m, callback,
+                                               link_netlink_destroy_callback, link);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
                         link_ref(link);
                 } else {
-                        r = sd_netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
-                                                  netdev_destroy_callback, netdev, 0, __func__);
+                        r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
+                                               netdev_destroy_callback, netdev);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
@@ -604,7 +594,7 @@ static int netdev_create(NetDev *netdev, Link *link,
 }
 
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
-int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
index 8c84a43971f60c785a9da30d331929b575cc31f5..bfe1094181ae9692898b9d4b37d8720c31488432 100644 (file)
@@ -5,13 +5,13 @@
 
 #include "conf-parser.h"
 #include "list.h"
+#include "../networkd-link.h"
 #include "time-util.h"
 
 typedef struct netdev_join_callback netdev_join_callback;
-typedef struct Link Link;
 
 struct netdev_join_callback {
-        sd_netlink_message_handler_t callback;
+        link_netlink_message_handler_t callback;
         Link *link;
 
         LIST_FIELDS(netdev_join_callback, callbacks);
@@ -153,13 +153,13 @@ void netdev_drop(NetDev *netdev);
 
 NetDev *netdev_unref(NetDev *netdev);
 NetDev *netdev_ref(NetDev *netdev);
-void netdev_destroy_callback(void *userdata);
+DEFINE_TRIVIAL_DESTRUCTOR(netdev_destroy_callback, NetDev, netdev_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref);
 
 int netdev_get(Manager *manager, const char *name, NetDev **ret);
 int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
 int netdev_get_mac(const char *ifname, struct ether_addr **ret);
-int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t cb);
+int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
 
 const char *netdev_kind_to_string(NetDevKind d) _const_;
 NetDevKind netdev_kind_from_string(const char *d) _pure_;
index 36f1fe7b03403c959d23422f9727b66010b7a704..684edddb5f5307a1ac25940097cebb7fce63e68a 100644 (file)
@@ -118,6 +118,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
                 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
+
                 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
                  * expecting to receive the prefixlen as a u16.
                  */
@@ -126,6 +127,16 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
         }
 
+        if (t->isatap >= 0) {
+                uint16_t flags = 0;
+
+                SET_FLAG(flags, SIT_ISATAP, t->isatap);
+
+                r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
+        }
+
         return r;
 }
 
@@ -761,6 +772,7 @@ static void sit_init(NetDev *n) {
         assert(t);
 
         t->pmtudisc = true;
+        t->isatap = -1;
 }
 
 static void vti_init(NetDev *n) {
index 51b61637ad44a92fcf25ed848f7e583d3826a022..8f511dd1f64a90cd8e68ab4a568df925eb25bf3c 100644 (file)
@@ -30,6 +30,7 @@ typedef struct Tunnel {
         int ipv6_flowlabel;
         int allow_localremote;
         int erspan_sequence;
+        int isatap;
 
         unsigned ttl;
         unsigned tos;
index f8139b52c3e0fe5d472d025320ba3b11ec81d47c..e8ea70a1edcb57bb453262853bca6085fa9c67f3 100644 (file)
@@ -1,7 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include "netdev/vxcan.h"
+#if HAVE_LINUX_CAN_VXCAN_H
+#include <linux/can/vxcan.h>
+#endif
+
 #include "missing.h"
+#include "netdev/vxcan.h"
 
 static int netdev_vxcan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         VxCan *v;
index 417672c4741c214c0cac8fdd5c161cb310738fe9..b5de19740f2959ebd6697b6a2b3e45af11de5972 100644 (file)
@@ -3,10 +3,6 @@
 
 typedef struct VxCan VxCan;
 
-#if HAVE_VXCAN_INFO_PEER
-#include <linux/can/vxcan.h>
-#endif
-
 #include "netdev/netdev.h"
 
 struct VxCan {
index e23dd13648eaad861d8135e772da03ee5267b6ab..4cb2eca3d2f8bdd1007d0c36089e6e1ca44d1874 100644 (file)
@@ -42,7 +42,6 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
 
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
-
         }
 
         if (!in_addr_is_null(v->local_family, &v->local)) {
@@ -54,20 +53,19 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
 
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LOCAL attribute: %m");
-
         }
 
         r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
 
-        if (v->ttl) {
+        if (v->ttl != 0) {
                 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
         }
 
-        if (v->tos) {
+        if (v->tos != 0) {
                 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
@@ -93,13 +91,13 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
 
-        if (v->fdb_ageing) {
+        if (v->fdb_ageing != 0) {
                 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
         }
 
-        if (v->max_fdb) {
+        if (v->max_fdb != 0) {
                 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m");
@@ -129,7 +127,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT attribute: %m");
 
-        if (v->port_range.low || v->port_range.high) {
+        if (v->port_range.low != 0 || v->port_range.high != 0) {
                 struct ifla_vxlan_port_range port_range;
 
                 port_range.low = htobe16(v->port_range.low);
@@ -214,9 +212,8 @@ int config_parse_port_range(const char *unit,
                             const char *rvalue,
                             void *data,
                             void *userdata) {
-        _cleanup_free_ char *word = NULL;
         VxLan *v = userdata;
-        unsigned low, high;
+        uint16_t low, high;
         int r;
 
         assert(filename);
@@ -224,30 +221,10 @@ int config_parse_port_range(const char *unit,
         assert(rvalue);
         assert(data);
 
-        r = extract_first_word(&rvalue, &word, NULL, 0);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract VXLAN port range, ignoring: %s", rvalue);
-                return 0;
-        }
-
-        if (r == 0)
-                return 0;
-
-        r = parse_range(word, &low, &high);
+        r = parse_ip_port_range(rvalue, &low, &high);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN port range '%s'", word);
-                return 0;
-        }
-
-        if (low <= 0 || low > 65535 || high <= 0 || high > 65535) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", word);
-                return 0;
-        }
-
-        if (high < low) {
                 log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Failed to parse VXLAN port range '%s'. Port range %u .. %u not valid", word, low, high);
+                           "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", rvalue);
                 return 0;
         }
 
index d5a0a19e9f212266b2051ca35e54c06e0d540edd..7fefef300468bcfc9692137c59634d0e0233e9b8 100644 (file)
@@ -300,7 +300,7 @@ static int wireguard_resolve_handler(sd_resolve_query *q,
                         return 0;
                 }
 
-                r = sd_event_source_set_destroy_callback(s, netdev_destroy_callback);
+                r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
                 if (r < 0) {
                         log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
                         return 0;
index 691bbf476194f27d701fb456006695a1bda998c6..94a12f8bfe7f868bc825fef7f04d63115b767c6b 100644 (file)
@@ -79,10 +79,36 @@ static int address_label_new_static(Network *network, const char *filename, unsi
         return 0;
 }
 
+static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(rtnl);
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->address_label_messages > 0);
+
+        link->address_label_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 set address label: %m");
+        else if (r >= 0)
+                manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->address_label_messages == 0)
+                log_link_debug(link, "Addresses label set");
+
+        return 1;
+}
+
 int address_label_configure(
                 AddressLabel *label,
                 Link *link,
-                sd_netlink_message_handler_t callback,
+                link_netlink_message_handler_t callback,
                 bool update) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
@@ -111,8 +137,9 @@ int address_label_configure(
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req,
+                               callback ?: address_label_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
index da506b2de48851cd9c1fd9c1ae8284d6178b1033..6922cb0faf85241fc4e2a30822106d7c780afe61 100644 (file)
@@ -32,7 +32,7 @@ void address_label_free(AddressLabel *label);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(AddressLabel*, address_label_free);
 
-int address_label_configure(AddressLabel *address, Link *link, sd_netlink_message_handler_t callback, bool update);
+int address_label_configure(AddressLabel *address, Link *link, link_netlink_message_handler_t callback, bool update);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_address_label);
 CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix);
index 09f041602ce25e8aa0c3502d4c75d736b2f167d5..9f0a22b82703325febcd7ed02a430074da3ad293 100644 (file)
@@ -114,9 +114,7 @@ void address_free(Address *address) {
         free(address);
 }
 
-static void address_hash_func(const void *b, struct siphash *state) {
-        const Address *a = b;
-
+static void address_hash_func(const Address *a, struct siphash *state) {
         assert(a);
 
         siphash24_compress(&a->family, sizeof(a->family), state);
@@ -149,8 +147,7 @@ static void address_hash_func(const void *b, struct siphash *state) {
         }
 }
 
-static int address_compare_func(const void *c1, const void *c2) {
-        const Address *a1 = c1, *a2 = c2;
+static int address_compare_func(const Address *a1, const Address *a2) {
         int r;
 
         r = CMP(a1->family, a2->family);
@@ -194,10 +191,7 @@ static int address_compare_func(const void *c1, const void *c2) {
         }
 }
 
-static const struct hash_ops address_hash_ops = {
-        .hash = address_hash_func,
-        .compare = address_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func);
 
 bool address_equal(Address *a1, Address *a2) {
         if (a1 == a2)
@@ -428,10 +422,27 @@ int address_get(Link *link,
         return -ENOENT;
 }
 
+static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EADDRNOTAVAIL)
+                log_link_warning_errno(link, r, "Could not drop address: %m");
+
+        return 1;
+}
+
 int address_remove(
                 Address *address,
                 Link *link,
-                sd_netlink_message_handler_t callback) {
+                link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         _cleanup_free_ char *b = NULL;
@@ -465,8 +476,9 @@ int address_remove(
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req,
+                               callback ?: address_remove_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -539,7 +551,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
 int address_configure(
                 Address *address,
                 Link *link,
-                sd_netlink_message_handler_t callback,
+                link_netlink_message_handler_t callback,
                 bool update) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
@@ -551,6 +563,7 @@ int address_configure(
         assert(link->ifindex > 0);
         assert(link->manager);
         assert(link->manager->rtnl);
+        assert(callback);
 
         /* If this is a new address, then refuse adding more than the limit */
         if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
@@ -644,8 +657,8 @@ int address_configure(
         if (r < 0)
                 return r;
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
+                               link_netlink_destroy_callback, link);
         if (r < 0) {
                 address_release(address);
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
index cd80741cb07677e95cfcfe3da8b916ed77e67437..4714c07d4da56e10afbdf57a718d3721f7403210 100644 (file)
@@ -54,8 +54,8 @@ int address_add(Link *link, int family, const union in_addr_union *in_addr, unsi
 int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
 int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
 int address_drop(Address *address);
-int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update);
-int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
+int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update);
+int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
 bool address_equal(Address *a1, Address *a2);
 bool address_is_ready(const Address *a);
 
index c7ca57d5e07ff4065095098054b6d0f88d267e72..1d18e29b7c164167fe2ce7048089397ffbdaa7e2 100644 (file)
@@ -135,8 +135,7 @@ static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint
         return cnt;
 }
 
-static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -195,8 +194,8 @@ int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32
                 return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
 
         /* send message to the kernel */
-        r = sd_netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
index 597791e02b863f0e81ceff0812cbd7b9dd33950b..31dbea94205ef9059998686bbd7d942ee10ec618 100644 (file)
@@ -14,9 +14,7 @@
 #include "string-util.h"
 #include "sysctl-util.h"
 
-static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
-                               void *userdata) {
-        Link *link = userdata;
+static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -216,8 +214,7 @@ static int dhcp_lease_lost(Link *link) {
                                         assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
                                         assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
 
-                                        route_remove(route, link,
-                                                     link_route_remove_handler);
+                                        route_remove(route, link, NULL);
                                 }
                         }
                 }
@@ -237,8 +234,7 @@ static int dhcp_lease_lost(Link *link) {
                                 route_gw->dst_prefixlen = 32;
                                 route_gw->scope = RT_SCOPE_LINK;
 
-                                route_remove(route_gw, link,
-                                             link_route_remove_handler);
+                                route_remove(route_gw, link, NULL);
                         }
 
                         r = route_new(&route);
@@ -246,8 +242,7 @@ static int dhcp_lease_lost(Link *link) {
                                 route->family = AF_INET;
                                 route->gw.in = gateway;
 
-                                route_remove(route, link,
-                                             link_route_remove_handler);
+                                route_remove(route, link, NULL);
                         }
                 }
 
@@ -261,7 +256,7 @@ static int dhcp_lease_lost(Link *link) {
                         address->in_addr.in = addr;
                         address->prefixlen = prefixlen;
 
-                        address_remove(address, link, link_address_remove_handler);
+                        address_remove(address, link, NULL);
                 }
         }
 
@@ -303,9 +298,7 @@ static int dhcp_lease_lost(Link *link) {
         return 0;
 }
 
-static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
-                                 void *userdata) {
-        Link *link = userdata;
+static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
index 40b8780e5697d1a9b524093785c4a6b80c598d5f..4b5c4b8b4b6a400004f389da0181c9b9c7609ef0 100644 (file)
@@ -24,13 +24,9 @@ static bool dhcp6_get_prefix_delegation(Link *link) {
         if (!link->network)
                 return false;
 
-        if (!IN_SET(link->network->router_prefix_delegation,
-                            RADV_PREFIX_DELEGATION_DHCP6,
-                            RADV_PREFIX_DELEGATION_BOTH)) {
-                return false;
-        }
-
-        return true;
+        return IN_SET(link->network->router_prefix_delegation,
+                      RADV_PREFIX_DELEGATION_DHCP6,
+                      RADV_PREFIX_DELEGATION_BOTH);
 }
 
 static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) {
@@ -100,8 +96,7 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
         return sd_radv_start(radv);
 }
 
-static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -247,8 +242,7 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
         return 0;
 }
 
-static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -406,9 +400,7 @@ int dhcp6_request_prefix_delegation(Link *link) {
         return 0;
 }
 
-static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
-                                 void *userdata) {
-        Link *link = userdata;
+static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
index c7742a93fb5d82734da565fa9a154699c0e9033c..324f6a5a1aad12d24d87f455748d5a35380532d0 100644 (file)
@@ -87,8 +87,7 @@ int fdb_entry_new_static(
         return 0;
 }
 
-static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -147,8 +146,8 @@ int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
         }
 
         /* send message to the kernel to update its internal static MAC table. */
-        r = sd_netlink_call_async(rtnl, NULL, req, set_fdb_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(rtnl, NULL, req, set_fdb_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
index 0f333175da6aa89688086542b1fe035709a31d70..3562e90535ddce1f5ea1736060a109d8581e06e3 100644 (file)
@@ -34,7 +34,7 @@ static int ipv4ll_address_lost(Link *link) {
         address->prefixlen = 16;
         address->scope = RT_SCOPE_LINK;
 
-        address_remove(address, link, link_address_remove_handler);
+        address_remove(address, link, NULL);
 
         r = route_new(&route);
         if (r < 0)
@@ -44,15 +44,14 @@ static int ipv4ll_address_lost(Link *link) {
         route->scope = RT_SCOPE_LINK;
         route->priority = IPV4LL_ROUTE_METRIC;
 
-        route_remove(route, link, link_route_remove_handler);
+        route_remove(route, link, NULL);
 
         link_check_ready(link);
 
         return 0;
 }
 
-static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -72,8 +71,7 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
         return 1;
 }
 
-static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
index 8d58406c3433e8c6d193fe23635a871a57e8a300..f594b27f7f081f6b948231677dec0090a85bc243 100644 (file)
@@ -135,8 +135,7 @@ int config_parse_ipv6_proxy_ndp_address(
         return 0;
 }
 
-static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -174,8 +173,8 @@ int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_netlink_call_async(rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
index db2dbef52c76fc77986a0eaec0b992180620ccc4..d575740e83fe5d10fd17c4275482c1619748bf84 100644 (file)
 #include "bus-util.h"
 #include "dhcp-identifier.h"
 #include "dhcp-lease-internal.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-lldp-tx.h"
 #include "networkd-manager.h"
 #include "networkd-ndisc.h"
+#include "networkd-neighbor.h"
 #include "networkd-radv.h"
 #include "networkd-routing-policy-rule.h"
 #include "set.h"
@@ -25,6 +28,7 @@
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 #include "virt.h"
 
@@ -590,14 +594,6 @@ static Link *link_free(Link *link) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
 
-void link_netlink_destroy_callback(void *userdata) {
-        Link *link = userdata;
-
-        assert(userdata);
-
-        link_unref(link);
-}
-
 int link_get(Manager *m, int ifindex, Link **ret) {
         Link *link;
 
@@ -724,7 +720,7 @@ static void link_enter_configured(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (link->state != LINK_STATE_SETTING_ROUTES)
+        if (link->state != LINK_STATE_CONFIGURING)
                 return;
 
         log_link_info(link, "Configured");
@@ -746,6 +742,12 @@ void link_check_ready(Link *link) {
         if (!link->network)
                 return;
 
+        if (!link->addresses_configured)
+                return;
+
+        if (!link->neighbors_configured)
+                return;
+
         if (!link->static_routes_configured)
                 return;
 
@@ -801,7 +803,7 @@ static int link_set_routing_policy_rule(Link *link) {
                         continue;
                 }
 
-                r = routing_policy_rule_configure(rule, link, link_routing_policy_rule_handler, false);
+                r = routing_policy_rule_configure(rule, link, NULL, false);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
                         link_enter_failed(link);
@@ -821,15 +823,13 @@ static int link_set_routing_policy_rule(Link *link) {
         return 0;
 }
 
-static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
         assert(link->route_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
-                      LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
-                      LINK_STATE_LINGER));
+        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
+                      LINK_STATE_FAILED, LINK_STATE_LINGER));
 
         link->route_messages--;
 
@@ -849,7 +849,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
         return 1;
 }
 
-static int link_enter_set_routes(Link *link) {
+static int link_request_set_routes(Link *link) {
         enum {
                 PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
                 PHASE_GATEWAY,     /* Second phase: Routes with a gateway */
@@ -860,11 +860,13 @@ static int link_enter_set_routes(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->state == LINK_STATE_SETTING_ADDRESSES);
+        assert(link->addresses_configured);
+        assert(link->address_messages == 0);
+        assert(link->state != _LINK_STATE_INVALID);
 
-        (void) link_set_routing_policy_rule(link);
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
-        link_set_state(link, LINK_STATE_SETTING_ROUTES);
+        (void) link_set_routing_policy_rule(link);
 
         /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
         for (phase = 0; phase < _PHASE_MAX; phase++)
@@ -892,26 +894,35 @@ static int link_enter_set_routes(Link *link) {
         return 0;
 }
 
-int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_request_set_neighbors(Link *link) {
+        Neighbor *neighbor;
         int r;
 
-        assert(m);
         assert(link);
-        assert(link->ifname);
+        assert(link->network);
+        assert(link->state != _LINK_STATE_INVALID);
 
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -ESRCH)
-                log_link_warning_errno(link, r, "Could not drop route: %m");
+        LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
+                r = neighbor_configure(neighbor, link, NULL);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "Could not set neighbor: %m");
+                        link_enter_failed(link);
+                        return r;
+                }
+        }
 
-        return 1;
+        if (link->neighbor_messages == 0) {
+                link->neighbors_configured = true;
+                link_check_ready(link);
+        } else
+                log_link_debug(link, "Setting neighbors");
+
+        return 0;
 }
 
-static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(rtnl);
@@ -919,7 +930,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         assert(link);
         assert(link->ifname);
         assert(link->address_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
+        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
                LINK_STATE_FAILED, LINK_STATE_LINGER));
 
         link->address_messages--;
@@ -935,39 +946,13 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
 
         if (link->address_messages == 0) {
                 log_link_debug(link, "Addresses set");
-                link_enter_set_routes(link);
+                link->addresses_configured = true;
+                link_request_set_routes(link);
         }
 
         return 1;
 }
 
-static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-        assert(link->address_label_messages > 0);
-
-        link->address_label_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 set address label: %m");
-        else if (r >= 0)
-                manager_rtnl_process_address(rtnl, m, link->manager);
-
-        if (link->address_label_messages == 0)
-                log_link_debug(link, "Addresses label set");
-
-        return 1;
-}
-
 static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
         _cleanup_free_ struct in_addr *addresses = NULL;
         size_t n_addresses = 0, n_allocated = 0;
@@ -1079,7 +1064,7 @@ static int link_set_bridge_fdb(Link *link) {
         return 0;
 }
 
-static int link_enter_set_addresses(Link *link) {
+static int link_request_set_addresses(Link *link) {
         AddressLabel *label;
         Address *ad;
         int r;
@@ -1092,7 +1077,9 @@ static int link_enter_set_addresses(Link *link) {
         if (r < 0)
                 return r;
 
-        link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
+        link_set_state(link, LINK_STATE_CONFIGURING);
+
+        link_request_set_neighbors(link);
 
         LIST_FOREACH(addresses, ad, link->network->static_addresses) {
                 r = address_configure(ad, link, address_handler, false);
@@ -1106,7 +1093,7 @@ static int link_enter_set_addresses(Link *link) {
         }
 
         LIST_FOREACH(labels, label, link->network->address_labels) {
-                r = address_label_configure(label, link, address_label_handler, false);
+                r = address_label_configure(label, link, NULL, false);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set address label: %m");
                         link_enter_failed(link);
@@ -1233,32 +1220,15 @@ static int link_enter_set_addresses(Link *link) {
                 log_link_debug(link, "Offering DHCPv4 leases");
         }
 
-        if (link->address_messages == 0)
-                link_enter_set_routes(link);
-        else
+        if (link->address_messages == 0) {
+                link->addresses_configured = true;
+                link_request_set_routes(link);
+        } else
                 log_link_debug(link, "Setting addresses");
 
         return 0;
 }
 
-int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
-
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EADDRNOTAVAIL)
-                log_link_warning_errno(link, r, "Could not drop address: %m");
-
-        return 1;
-}
-
 static int link_set_bridge_vlan(Link *link) {
         int r = 0;
 
@@ -1285,8 +1255,7 @@ static int link_set_proxy_arp(Link *link) {
         return 0;
 }
 
-static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -1304,8 +1273,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
 
 static int link_configure_after_setting_mtu(Link *link);
 
-static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(m);
@@ -1366,8 +1334,8 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append MTU: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_mtu_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_mtu_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1377,8 +1345,7 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         return 0;
 }
 
-static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(m);
@@ -1437,8 +1404,8 @@ static int link_set_flags(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1495,7 +1462,12 @@ static int link_set_bridge(Link *link) {
                 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
+        }
 
+        if (link->network->multicast_to_unicast >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
         }
 
         if (link->network->cost != 0) {
@@ -1503,6 +1475,7 @@ static int link_set_bridge(Link *link) {
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
         }
+
         if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
                 r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
                 if (r < 0)
@@ -1513,8 +1486,8 @@ static int link_set_bridge(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_set_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1566,8 +1539,8 @@ static int link_bond_set(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r,  "Could not send rtnetlink message: %m");
 
@@ -1766,8 +1739,7 @@ bool link_has_carrier(Link *link) {
         return false;
 }
 
-static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -1859,8 +1831,8 @@ int link_up(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1885,8 +1857,8 @@ static int link_up_can(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1975,8 +1947,8 @@ static int link_set_can(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to close netlink container: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, m, link_set_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, m, link_set_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1995,8 +1967,7 @@ static int link_set_can(Link *link) {
         return r;
 }
 
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -2033,8 +2004,8 @@ int link_down(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -2338,11 +2309,10 @@ static int link_joined(Link *link) {
         if (!link_has_carrier(link) && !link->network->configure_without_carrier)
                 return 0;
 
-        return link_enter_set_addresses(link);
+        return link_request_set_addresses(link);
 }
 
-static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -2376,7 +2346,7 @@ static int link_enter_join_netdev(Link *link) {
         assert(link->network);
         assert(link->state == LINK_STATE_PENDING);
 
-        link_set_state(link, LINK_STATE_ENSLAVING);
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
         link_dirty(link);
 
@@ -2691,7 +2661,7 @@ static int link_drop_foreign_config(Link *link) {
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Failed to add address: %m");
                 } else {
-                        r = address_remove(address, link, link_address_remove_handler);
+                        r = address_remove(address, link, NULL);
                         if (r < 0)
                                 return r;
                 }
@@ -2707,7 +2677,7 @@ static int link_drop_foreign_config(Link *link) {
                         if (r < 0)
                                 return r;
                 } else {
-                        r = route_remove(route, link, link_route_remove_handler);
+                        r = route_remove(route, link, NULL);
                         if (r < 0)
                                 return r;
                 }
@@ -2727,7 +2697,7 @@ static int link_drop_config(Link *link) {
                 if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
                         continue;
 
-                r = address_remove(address, link, link_address_remove_handler);
+                r = address_remove(address, link, NULL);
                 if (r < 0)
                         return r;
 
@@ -2746,7 +2716,7 @@ static int link_drop_config(Link *link) {
                 if (route->protocol == RTPROT_KERNEL)
                         continue;
 
-                r = route_remove(route, link, link_route_remove_handler);
+                r = route_remove(route, link, NULL);
                 if (r < 0)
                         return r;
         }
@@ -3165,8 +3135,8 @@ static int link_initialized_and_synced(Link *link) {
         return 1;
 }
 
-static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        (void) link_initialized_and_synced(userdata);
+static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        (void) link_initialized_and_synced(link);
         return 1;
 }
 
@@ -3199,8 +3169,8 @@ int link_initialized(Link *link, sd_device *device) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_initialized_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_initialized_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return r;
 
@@ -3489,7 +3459,7 @@ static int link_carrier_gained(Link *link) {
                         return r;
                 }
 
-                r = link_enter_set_addresses(link);
+                r = link_request_set_addresses(link);
                 if (r < 0)
                         return r;
         }
@@ -3572,7 +3542,7 @@ int link_update(Link *link, sd_netlink_message *m) {
 
         if (link->state == LINK_STATE_LINGER) {
                 log_link_info(link, "Link readded");
-                link_set_state(link, LINK_STATE_ENSLAVING);
+                link_set_state(link, LINK_STATE_CONFIGURING);
 
                 r = link_new_carrier_maps(link);
                 if (r < 0)
@@ -4100,9 +4070,7 @@ void link_clean(Link *link) {
 
 static const char* const link_state_table[_LINK_STATE_MAX] = {
         [LINK_STATE_PENDING] = "pending",
-        [LINK_STATE_ENSLAVING] = "configuring",
-        [LINK_STATE_SETTING_ADDRESSES] = "configuring",
-        [LINK_STATE_SETTING_ROUTES] = "configuring",
+        [LINK_STATE_CONFIGURING] = "configuring",
         [LINK_STATE_CONFIGURED] = "configured",
         [LINK_STATE_UNMANAGED] = "unmanaged",
         [LINK_STATE_FAILED] = "failed",
index 7261b3142af7e5fc59ce113f052ea44bdf9c4b31..00e68fdfaab6975d753acc4eee9b52ec0f3368bb 100644 (file)
@@ -19,9 +19,7 @@
 
 typedef enum LinkState {
         LINK_STATE_PENDING,
-        LINK_STATE_ENSLAVING,
-        LINK_STATE_SETTING_ADDRESSES,
-        LINK_STATE_SETTING_ROUTES,
+        LINK_STATE_CONFIGURING,
         LINK_STATE_CONFIGURED,
         LINK_STATE_UNMANAGED,
         LINK_STATE_FAILED,
@@ -72,6 +70,7 @@ typedef struct Link {
 
         unsigned address_messages;
         unsigned address_label_messages;
+        unsigned neighbor_messages;
         unsigned route_messages;
         unsigned routing_policy_rule_messages;
         unsigned routing_policy_rule_remove_messages;
@@ -82,6 +81,8 @@ typedef struct Link {
         Set *routes;
         Set *routes_foreign;
 
+        bool addresses_configured;
+
         sd_dhcp_client *dhcp_client;
         sd_dhcp_lease *dhcp_lease;
         char *lease_file;
@@ -97,6 +98,8 @@ typedef struct Link {
         bool ipv4ll_address:1;
         bool ipv4ll_route:1;
 
+        bool neighbors_configured;
+
         bool static_routes_configured;
         bool routing_policy_rules_configured;
         bool setting_mtu;
@@ -126,12 +129,14 @@ typedef struct Link {
         Hashmap *bound_to_links;
 } Link;
 
+typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
+
 DUID *link_get_duid(Link *link);
 int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
 
 Link *link_unref(Link *link);
 Link *link_ref(Link *link);
-void link_netlink_destroy_callback(void *userdata);
+DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
 
 int link_get(Manager *m, int ifindex, Link **ret);
 int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
@@ -140,9 +145,6 @@ void link_drop(Link *link);
 int link_up(Link *link);
 int link_down(Link *link);
 
-int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-
 void link_enter_failed(Link *link);
 int link_initialized(Link *link, sd_device *device);
 
index de39568eca82a5325ee6a075cc8c96f9b8ff266d..8fd6365e68b42870ba5c719d91dcfce59ccc383c 100644 (file)
@@ -5,9 +5,10 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "hostname-util.h"
+#include "missing_network.h"
 #include "networkd-lldp-tx.h"
 #include "networkd-manager.h"
 #include "parse-util.h"
index 3b1ae0b41fcf60371d7d39d2889e15953ed0e30a..81c81f18af0253eceae2b8d2496d2e91066fc806 100644 (file)
@@ -23,6 +23,7 @@
 #include "path-util.h"
 #include "set.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "virt.h"
 
 /* use 8 MB for receive socket kernel queue. */
@@ -1237,8 +1238,7 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
         return hashmap_get(m->dhcp6_prefixes, addr);
 }
 
-static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -1250,24 +1250,17 @@ static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, void *
         return 0;
 }
 
-static void dhcp6_prefixes_hash_func(const void *p, struct siphash *state) {
-        const struct in6_addr *addr = p;
-
-        assert(p);
+static void dhcp6_prefixes_hash_func(const struct in6_addr *addr, struct siphash *state) {
+        assert(addr);
 
         siphash24_compress(addr, sizeof(*addr), state);
 }
 
-static int dhcp6_prefixes_compare_func(const void *_a, const void *_b) {
-        const struct in6_addr *a = _a, *b = _b;
-
+static int dhcp6_prefixes_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
         return memcmp(a, b, sizeof(*a));
 }
 
-static const struct hash_ops dhcp6_prefixes_hash_ops = {
-        .hash = dhcp6_prefixes_hash_func,
-        .compare = dhcp6_prefixes_compare_func,
-};
+DEFINE_PRIVATE_HASH_OPS(dhcp6_prefixes_hash_ops, struct in6_addr, dhcp6_prefixes_hash_func, dhcp6_prefixes_compare_func);
 
 int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
         _cleanup_free_ char *buf = NULL;
@@ -1296,8 +1289,7 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
         return hashmap_put(m->dhcp6_prefixes, addr, link);
 }
 
-static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
index 8596db11c7e4202e1cb9e7f9f84800bda06050a2..80bfd2cba1232a9aabb8d736365eb86d73d3589f 100644 (file)
@@ -16,8 +16,7 @@
 #define NDISC_RDNSS_MAX 64U
 #define NDISC_PREFIX_LFT_MIN 7200U
 
-static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int ndisc_netlink_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -111,7 +110,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
         route->mtu = mtu;
 
-        r = route_configure(route, link, ndisc_route_handler);
+        r = route_configure(route, link, ndisc_netlink_message_handler);
         if (r < 0) {
                 log_link_warning_errno(link, r, "Could not set default route: %m");
                 link_enter_failed(link);
@@ -199,7 +198,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         if (address->cinfo.ifa_valid == 0)
                 return 0;
 
-        r = address_configure(address, link, ndisc_route_handler, true);
+        r = address_configure(address, link, ndisc_netlink_message_handler, true);
         if (r < 0) {
                 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
                 link_enter_failed(link);
@@ -249,7 +248,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
 
-        r = route_configure(route, link, ndisc_route_handler);
+        r = route_configure(route, link, ndisc_netlink_message_handler);
         if (r < 0) {
                 log_link_warning_errno(link, r, "Could not set prefix route: %m");
                 link_enter_failed(link);
@@ -310,7 +309,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get route address: %m");
 
-        r = route_configure(route, link, ndisc_route_handler);
+        r = route_configure(route, link, ndisc_netlink_message_handler);
         if (r < 0) {
                 log_link_warning_errno(link, r, "Could not set additional route: %m");
                 link_enter_failed(link);
@@ -322,22 +321,15 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         return 0;
 }
 
-static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) {
-        const NDiscRDNSS *x = p;
-
+static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
         siphash24_compress(&x->address, sizeof(x->address), state);
 }
 
-static int ndisc_rdnss_compare_func(const void *_a, const void *_b) {
-        const NDiscRDNSS *a = _a, *b = _b;
-
+static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
         return memcmp(&a->address, &b->address, sizeof(a->address));
 }
 
-static const struct hash_ops ndisc_rdnss_hash_ops = {
-        .hash = ndisc_rdnss_hash_func,
-        .compare = ndisc_rdnss_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func);
 
 static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
         uint32_t lifetime;
@@ -411,22 +403,15 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
         return 0;
 }
 
-static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) {
-        const NDiscDNSSL *x = p;
-
+static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
         siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
 }
 
-static int ndisc_dnssl_compare_func(const void *_a, const void *_b) {
-        const NDiscDNSSL *a = _a, *b = _b;
-
+static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
         return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
 }
 
-static const struct hash_ops ndisc_dnssl_hash_ops = {
-        .hash = ndisc_dnssl_hash_func,
-        .compare = ndisc_dnssl_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func);
 
 static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
         _cleanup_strv_free_ char **l = NULL;
diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c
new file mode 100644 (file)
index 0000000..254a60b
--- /dev/null
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "hashmap.h"
+#include "in-addr-util.h"
+#include "netlink-util.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "networkd-neighbor.h"
+
+void neighbor_free(Neighbor *neighbor) {
+        if (!neighbor)
+                return;
+
+        if (neighbor->network) {
+                LIST_REMOVE(neighbors, neighbor->network->neighbors, neighbor);
+                assert(neighbor->network->n_neighbors > 0);
+                neighbor->network->n_neighbors--;
+
+                if (neighbor->section) {
+                        hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
+                        network_config_section_free(neighbor->section);
+                }
+        }
+
+        free(neighbor);
+}
+
+static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
+        int r;
+
+        assert(network);
+        assert(ret);
+        assert(!!filename == (section_line > 0));
+
+        if (filename) {
+                r = network_config_section_new(filename, section_line, &n);
+                if (r < 0)
+                        return r;
+
+                neighbor = hashmap_get(network->neighbors_by_section, n);
+                if (neighbor) {
+                        *ret = TAKE_PTR(neighbor);
+
+                        return 0;
+                }
+        }
+
+        neighbor = new(Neighbor, 1);
+        if (!neighbor)
+                return -ENOMEM;
+
+        *neighbor = (Neighbor) {
+                .network = network,
+                .family = AF_UNSPEC,
+        };
+
+        LIST_APPEND(neighbors, network->neighbors, neighbor);
+        network->n_neighbors++;
+
+        if (filename) {
+                neighbor->section = TAKE_PTR(n);
+
+                r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(neighbor);
+
+        return 0;
+}
+
+static int neighbor_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(link);
+        assert(link->neighbor_messages > 0);
+
+        link->neighbor_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 set neighbor: %m");
+
+        if (link->neighbor_messages == 0) {
+                log_link_debug(link, "Neighbors set");
+                link->neighbors_configured = true;
+                link_check_ready(link);
+        }
+
+        return 1;
+}
+
+int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
+
+        assert(neighbor);
+        assert(link);
+        assert(link->ifindex > 0);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+
+        if (neighbor->family == AF_UNSPEC)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor without Address= configured");
+        if (!neighbor->mac_configured)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor without MACAddress= configured");
+
+        r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
+                                          link->ifindex, neighbor->family);
+        if (r < 0)
+                return log_error_errno(r, "Could not allocate RTM_NEWNEIGH message: %m");
+
+        r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
+        if (r < 0)
+                return log_error_errno(r, "Could not set state: %m");
+
+        r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE);
+        if (r < 0)
+                return log_error_errno(r, "Could not set flags: %m");
+
+        r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, &neighbor->mac);
+        if (r < 0)
+                return log_error_errno(r, "Could not append NDA_LLADDR attribute: %m");
+
+        switch (neighbor->family) {
+        case AF_INET6:
+                r = sd_netlink_message_append_in6_addr(req, NDA_DST, &neighbor->in_addr.in6);
+                if (r < 0)
+                        return log_error_errno(r, "Could not append NDA_DST attribute: %m");
+                break;
+        case AF_INET:
+                r = sd_netlink_message_append_in_addr(req, NDA_DST, &neighbor->in_addr.in);
+                if (r < 0)
+                        return log_error_errno(r, "Could not append NDA_DST attribute: %m");
+                break;
+        default:
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor with invalid address family");
+        }
+
+        r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_handler,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_error_errno(r, "Could not send rtnetlink message: %m");
+
+        link->neighbor_messages++;
+        link_ref(link);
+
+        return 0;
+}
+
+int config_parse_neighbor_address(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_(neighbor_freep) Neighbor *n = NULL;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = neighbor_new_static(network, filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor Address is invalid, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(n);
+
+        return 0;
+}
+
+int config_parse_neighbor_hwaddr(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_(neighbor_freep) Neighbor *n = NULL;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = neighbor_new_static(network, filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        r = ether_addr_from_string(rvalue, &n->mac);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor MACAddress is invalid, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        n->mac_configured = true;
+        TAKE_PTR(n);
+
+        return 0;
+}
diff --git a/src/network/networkd-neighbor.h b/src/network/networkd-neighbor.h
new file mode 100644 (file)
index 0000000..094bf79
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-netlink.h"
+
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "in-addr-util.h"
+#include "list.h"
+#include "macro.h"
+
+typedef struct Neighbor Neighbor;
+
+#include "networkd-link.h"
+#include "networkd-network.h"
+
+struct Neighbor {
+        Network *network;
+        Link *link;
+        NetworkConfigSection *section;
+
+        int family;
+        union in_addr_union in_addr;
+        bool mac_configured;
+        struct ether_addr mac;
+
+        LIST_FIELDS(Neighbor, neighbors);
+};
+
+void neighbor_free(Neighbor *neighbor);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Neighbor*, neighbor_free);
+
+int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_hwaddr);
index 378b63af8c0ce36774a333af8b3b778710072ca0..00605c0b92683e6f846ba24a21bc1b1be78c1c4c 100644 (file)
@@ -93,6 +93,8 @@ Address.AutoJoin,                       config_parse_address_flags,
 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
+Neighbor.Address,                       config_parse_neighbor_address,                  0,                             0
+Neighbor.MACAddress,                    config_parse_neighbor_hwaddr,                   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
@@ -101,9 +103,10 @@ RoutingPolicyRule.From,                 config_parse_routing_policy_rule_prefix,
 RoutingPolicyRule.To,                   config_parse_routing_policy_rule_prefix,        0,                             0
 RoutingPolicyRule.IncomingInterface,    config_parse_routing_policy_rule_device,        0,                             0
 RoutingPolicyRule.OutgoingInterface,    config_parse_routing_policy_rule_device,        0,                             0
-RoutingPolicyRule.Protocol,             config_parse_routing_policy_rule_protocol,      0,                             0
+RoutingPolicyRule.IPProtocol,           config_parse_routing_policy_rule_ip_protocol,   0,                             0
 RoutingPolicyRule.SourcePort,           config_parse_routing_policy_rule_port_range,    0,                             0
 RoutingPolicyRule.DestinationPort,      config_parse_routing_policy_rule_port_range,    0,                             0
+RoutingPolicyRule.InvertRule,           config_parse_routing_policy_rule_invert,        0,                             0
 Route.Gateway,                          config_parse_gateway,                           0,                             0
 Route.Destination,                      config_parse_destination,                       0,                             0
 Route.Source,                           config_parse_destination,                       0,                             0
@@ -162,6 +165,7 @@ Bridge.HairPin,                         config_parse_tristate,
 Bridge.FastLeave,                       config_parse_tristate,                          0,                             offsetof(Network, fast_leave)
 Bridge.AllowPortToBeRoot,               config_parse_tristate,                          0,                             offsetof(Network, allow_port_to_be_root)
 Bridge.UnicastFlood,                    config_parse_tristate,                          0,                             offsetof(Network, unicast_flood)
+Bridge.MulticastToUnicast,              config_parse_tristate,                          0,                             offsetof(Network, multicast_to_unicast)
 Bridge.Priority,                        config_parse_bridge_port_priority,              0,                             offsetof(Network, priority)
 BridgeFDB.MACAddress,                   config_parse_fdb_hwaddr,                        0,                             0
 BridgeFDB.VLANId,                       config_parse_fdb_vlan_id,                       0,                             0
index 989c92322bb3d5ad489fe896f7ff41cec14bf87d..6f14fb270ebbfeec618a3da3be8c4a6fc0503380 100644 (file)
@@ -10,6 +10,7 @@
 #include "fd-util.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
+#include "missing_network.h"
 #include "network-internal.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
 #include "strv.h"
 #include "util.h"
 
-static void network_config_hash_func(const void *p, struct siphash *state) {
-        const NetworkConfigSection *c = p;
-
+static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
         siphash24_compress(c->filename, strlen(c->filename), state);
         siphash24_compress(&c->line, sizeof(c->line), state);
 }
 
-static int network_config_compare_func(const void *a, const void *b) {
-        const NetworkConfigSection *x = a, *y = b;
+static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
         int r;
 
         r = strcmp(x->filename, y->filename);
@@ -39,10 +37,7 @@ static int network_config_compare_func(const void *a, const void *b) {
         return CMP(x->line, y->line);
 }
 
-const struct hash_ops network_config_hash_ops = {
-        .hash = network_config_hash_func,
-        .compare = network_config_compare_func,
-};
+DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
 
 int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
         NetworkConfigSection *cs;
@@ -168,6 +163,7 @@ int network_load_one(Manager *manager, const char *filename) {
                 .fast_leave = -1,
                 .allow_port_to_be_root = -1,
                 .unicast_flood = -1,
+                .multicast_to_unicast = -1,
                 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
 
                 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
@@ -214,6 +210,7 @@ int network_load_one(Manager *manager, const char *filename) {
                               "Link\0"
                               "Network\0"
                               "Address\0"
+                              "Neighbor\0"
                               "IPv6AddressLabel\0"
                               "RoutingPolicyRule\0"
                               "Route\0"
@@ -304,6 +301,7 @@ void network_free(Network *network) {
         IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
         RoutingPolicyRule *rule;
         FdbEntry *fdb_entry;
+        Neighbor *neighbor;
         AddressLabel *label;
         Prefix *prefix;
         Address *address;
@@ -354,6 +352,9 @@ void network_free(Network *network) {
         while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
                 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
 
+        while ((neighbor = network->neighbors))
+                neighbor_free(neighbor);
+
         while ((label = network->address_labels))
                 address_label_free(label);
 
@@ -366,6 +367,7 @@ void network_free(Network *network) {
         hashmap_free(network->addresses_by_section);
         hashmap_free(network->routes_by_section);
         hashmap_free(network->fdb_entries_by_section);
+        hashmap_free(network->neighbors_by_section);
         hashmap_free(network->address_labels_by_section);
         hashmap_free(network->prefixes_by_section);
         hashmap_free(network->rules_by_section);
@@ -657,7 +659,7 @@ int config_parse_domains(
                         domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
 
                 } else {
-                        r = dns_name_normalize(domain, &normalized);
+                        r = dns_name_normalize(domain, 0, &normalized);
                         if (r < 0) {
                                 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
                                 continue;
index 5c1fccbc41e346d26e6957478a3c4a61856963cf..7f64c3883983bba9a125f38482cffcef67320890 100644 (file)
@@ -15,6 +15,7 @@
 #include "networkd-fdb.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-lldp-tx.h"
+#include "networkd-neighbor.h"
 #include "networkd-radv.h"
 #include "networkd-route.h"
 #include "networkd-routing-policy-rule.h"
@@ -183,6 +184,7 @@ struct Network {
         int fast_leave;
         int allow_port_to_be_root;
         int unicast_flood;
+        int multicast_to_unicast;
         uint32_t cost;
         uint16_t priority;
 
@@ -234,6 +236,7 @@ struct Network {
         LIST_HEAD(Route, static_routes);
         LIST_HEAD(FdbEntry, static_fdb_entries);
         LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
+        LIST_HEAD(Neighbor, neighbors);
         LIST_HEAD(AddressLabel, address_labels);
         LIST_HEAD(Prefix, static_prefixes);
         LIST_HEAD(RoutingPolicyRule, rules);
@@ -242,6 +245,7 @@ struct Network {
         unsigned n_static_routes;
         unsigned n_static_fdb_entries;
         unsigned n_ipv6_proxy_ndp_addresses;
+        unsigned n_neighbors;
         unsigned n_address_labels;
         unsigned n_static_prefixes;
         unsigned n_rules;
@@ -249,6 +253,7 @@ struct Network {
         Hashmap *addresses_by_section;
         Hashmap *routes_by_section;
         Hashmap *fdb_entries_by_section;
+        Hashmap *neighbors_by_section;
         Hashmap *address_labels_by_section;
         Hashmap *prefixes_by_section;
         Hashmap *rules_by_section;
index 346d64953b619e79e6f74612d24a20b792ad62af..92cead052a66797a67bbbc054e38a2e65c02420f 100644 (file)
@@ -494,9 +494,16 @@ int radv_configure(Link *link) {
         if (IN_SET(link->network->router_prefix_delegation,
                    RADV_PREFIX_DELEGATION_STATIC,
                    RADV_PREFIX_DELEGATION_BOTH)) {
+
                 LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
                         r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
-                        if (r != -EEXIST && r < 0)
+                        if (r == -EEXIST)
+                                continue;
+                        if (r == -ENOEXEC) {
+                                log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
+                                continue;
+                        }
+                        if (r < 0)
                                 return r;
                 }
         }
index 2f70844d47137ecb9b61fb30c89f8fea153d7338..5553a7e3bd1b086c3cf46a3276521226328ef238 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "in-addr-util.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "networkd-manager.h"
 #include "networkd-route.h"
@@ -142,9 +143,7 @@ void route_free(Route *route) {
         free(route);
 }
 
-static void route_hash_func(const void *b, struct siphash *state) {
-        const Route *route = b;
-
+static void route_hash_func(const Route *route, struct siphash *state) {
         assert(route);
 
         siphash24_compress(&route->family, sizeof(route->family), state);
@@ -167,8 +166,7 @@ static void route_hash_func(const void *b, struct siphash *state) {
         }
 }
 
-static int route_compare_func(const void *_a, const void *_b) {
-        const Route *a = _a, *b = _b;
+static int route_compare_func(const Route *a, const Route *b) {
         int r;
 
         r = CMP(a->family, b->family);
@@ -201,10 +199,7 @@ static int route_compare_func(const void *_a, const void *_b) {
         }
 }
 
-static const struct hash_ops route_hash_ops = {
-        .hash = route_hash_func,
-        .compare = route_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(route_hash_ops, Route, route_hash_func, route_compare_func);
 
 bool route_equal(Route *r1, Route *r2) {
         if (r1 == r2)
@@ -378,8 +373,25 @@ void route_update(Route *route,
         route->type = type;
 }
 
+static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -ESRCH)
+                log_link_warning_errno(link, r, "Could not drop route: %m");
+
+        return 1;
+}
+
 int route_remove(Route *route, Link *link,
-                 sd_netlink_message_handler_t callback) {
+                 link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
@@ -454,8 +466,9 @@ int route_remove(Route *route, Link *link,
                         return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
         }
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req,
+                               callback ?: route_remove_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -470,7 +483,7 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
 
         assert(route);
 
-        r = route_remove(route, route->link, link_route_remove_handler);
+        r = route_remove(route, route->link, NULL);
         if (r < 0)
                 log_warning_errno(r, "Could not remove route: %m");
         else
@@ -482,7 +495,7 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
 int route_configure(
                 Route *route,
                 Link *link,
-                sd_netlink_message_handler_t callback) {
+                link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
@@ -494,6 +507,7 @@ int route_configure(
         assert(link->manager->rtnl);
         assert(link->ifindex > 0);
         assert(IN_SET(route->family, AF_INET, AF_INET6));
+        assert(callback);
 
         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())
@@ -635,8 +649,8 @@ int route_configure(
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -678,8 +692,7 @@ int config_parse_gateway(
 
         Network *network = userdata;
         _cleanup_(route_freep) Route *n = NULL;
-        union in_addr_union buffer;
-        int r, f;
+        int r;
 
         assert(filename);
         assert(section);
@@ -697,14 +710,12 @@ int config_parse_gateway(
         if (r < 0)
                 return r;
 
-        r = in_addr_from_string_auto(rvalue, &f, &buffer);
+        r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
-        n->family = f;
-        n->gw = buffer;
         TAKE_PTR(n);
 
         return 0;
@@ -724,8 +735,7 @@ int config_parse_preferred_src(
 
         Network *network = userdata;
         _cleanup_(route_freep) Route *n = NULL;
-        union in_addr_union buffer;
-        int r, f;
+        int r;
 
         assert(filename);
         assert(section);
@@ -737,15 +747,13 @@ int config_parse_preferred_src(
         if (r < 0)
                 return r;
 
-        r = in_addr_from_string_auto(rvalue, &f, &buffer);
+        r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                            "Preferred source is invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
-        n->family = f;
-        n->prefsrc = buffer;
         TAKE_PTR(n);
 
         return 0;
@@ -765,8 +773,8 @@ int config_parse_destination(
 
         Network *network = userdata;
         _cleanup_(route_freep) Route *n = NULL;
-        union in_addr_union buffer;
-        unsigned char prefixlen;
+        union in_addr_union *buffer;
+        unsigned char *prefixlen;
         int r;
 
         assert(filename);
@@ -779,29 +787,23 @@ int config_parse_destination(
         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,
-                                   "Route %s= prefix is invalid, ignoring assignment: %s",
-                                   lvalue, rvalue);
-                        return 0;
-                }
-
-                n->family = AF_INET6;
-        } else
-                n->family = AF_INET;
-
         if (streq(lvalue, "Destination")) {
-                n->dst = buffer;
-                n->dst_prefixlen = prefixlen;
+                buffer = &n->dst;
+                prefixlen = &n->dst_prefixlen;
         } else if (streq(lvalue, "Source")) {
-                n->src = buffer;
-                n->src_prefixlen = prefixlen;
+                buffer = &n->src;
+                prefixlen = &n->src_prefixlen;
         } else
                 assert_not_reached(lvalue);
 
+        r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Route %s= prefix is invalid, ignoring assignment: %s",
+                           lvalue, rvalue);
+                return 0;
+        }
+
         TAKE_PTR(n);
         return 0;
 }
index fe000d61b88adc4619ebbd3ef1ee0d11db90a6eb..4eddf5194fa7edd82c084bcc8c28668232df207b 100644 (file)
@@ -45,8 +45,8 @@ struct Route {
 int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret);
 int route_new(Route **ret);
 void route_free(Route *route);
-int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback);
+int route_remove(Route *route, Link *link, link_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);
index 1b2222cada6dca371d7b2b888e77815d0518b2b3..2dc78622cecf9a7853b7a86271f8c100d6ae00ac 100644 (file)
@@ -6,11 +6,11 @@
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "fileio.h"
+#include "ip-protocol-list.h"
 #include "networkd-routing-policy-rule.h"
 #include "netlink-util.h"
 #include "networkd-manager.h"
 #include "parse-util.h"
-#include "socket-protocol-list.h"
 #include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -56,9 +56,7 @@ void routing_policy_rule_free(RoutingPolicyRule *rule) {
         free(rule);
 }
 
-static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
-        const RoutingPolicyRule *rule = b;
-
+static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
         assert(rule);
 
         siphash24_compress(&rule->family, sizeof(rule->family), state);
@@ -94,8 +92,7 @@ static void routing_policy_rule_hash_func(const void *b, struct siphash *state)
         }
 }
 
-static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
-        const RoutingPolicyRule *a = _a, *b = _b;
+static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
         int r;
 
         r = CMP(a->family, b->family);
@@ -157,10 +154,7 @@ static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
         }
 }
 
-const struct hash_ops routing_policy_rule_hash_ops = {
-        .hash = routing_policy_rule_hash_func,
-        .compare = routing_policy_rule_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
 
 int routing_policy_rule_get(Manager *m,
                             int family,
@@ -341,8 +335,7 @@ int routing_policy_rule_add_foreign(Manager *m,
         return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret);
 }
 
-static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(m);
@@ -361,7 +354,7 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
         return 1;
 }
 
-int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
+int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
@@ -404,8 +397,9 @@ int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *lin
                         return log_error_errno(r, "Could not set destination prefix length: %m");
         }
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, m, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, m,
+                               callback ?: routing_policy_rule_remove_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -461,8 +455,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
         return 0;
 }
 
-int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(rtnl);
@@ -489,7 +482,7 @@ int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, vo
         return 1;
 }
 
-int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
+int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback, bool update) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
@@ -595,10 +588,17 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlin
                         return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
         }
 
+        if (rule->invert_rule) {
+                r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
+                if (r < 0)
+                        return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
+        }
+
         rule->link = link;
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, m, callback,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, m,
+                               callback ?: routing_policy_rule_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -802,8 +802,8 @@ int config_parse_routing_policy_rule_prefix(
 
         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
-        union in_addr_union buffer;
-        uint8_t prefixlen;
+        union in_addr_union *buffer;
+        uint8_t *prefixlen;
         int r;
 
         assert(filename);
@@ -816,24 +816,18 @@ int config_parse_routing_policy_rule_prefix(
         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;
+                buffer = &n->to;
+                prefixlen = &n->to_prefixlen;
         } else {
-                n->from = buffer;
-                n->from_prefixlen = prefixlen;
+                buffer = &n->from;
+                prefixlen = &n->from_prefixlen;
+        }
+
+        r = in_addr_prefix_from_string_auto(rvalue, &n->family, 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 = NULL;
@@ -932,7 +926,7 @@ int config_parse_routing_policy_rule_port_range(
         return 0;
 }
 
-int config_parse_routing_policy_rule_protocol(
+int config_parse_routing_policy_rule_ip_protocol(
                 const char *unit,
                 const char *filename,
                 unsigned line,
@@ -958,18 +952,52 @@ int config_parse_routing_policy_rule_protocol(
         if (r < 0)
                 return r;
 
-        r = socket_protocol_from_name(rvalue);
+        r = parse_ip_protocol(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule protocol, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
                 return 0;
         }
 
-        if (!IN_SET(r, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid protocol '%s'. Protocol should be tcp/udp/sctp, ignoring", rvalue);
+        n->protocol = r;
+
+        n = NULL;
+
+        return 0;
+}
+
+int config_parse_routing_policy_rule_invert(
+                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_freep) 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 = parse_boolean(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
                 return 0;
         }
 
-        n->protocol = r;
+        n->invert_rule = r;
 
         n = NULL;
 
@@ -1066,14 +1094,14 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
                 }
 
                 if (rule->sport.start != 0 || rule->sport.end != 0) {
-                        fprintf(f, "%ssourcesport=%hhu-%hhu",
+                        fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
                                 space ? " " : "",
                                 rule->sport.start, rule->sport.end);
                         space = true;
                 }
 
                 if (rule->dport.start != 0 || rule->dport.end != 0) {
-                        fprintf(f, "%sdestinationport=%hhu-%hhu",
+                        fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
                                 space ? " " : "",
                                 rule->dport.start, rule->dport.end);
                         space = true;
@@ -1123,8 +1151,6 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                 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)
@@ -1137,26 +1163,23 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
                                 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;
+                                union in_addr_union *buffer;
+                                uint8_t *prefixlen;
 
                                 if (streq(a, "to")) {
-                                        rule->to = buffer;
-                                        rule->to_prefixlen = prefixlen;
+                                        buffer = &rule->to;
+                                        prefixlen = &rule->to_prefixlen;
                                 } else {
-                                        rule->from = buffer;
-                                        rule->from_prefixlen = prefixlen;
+                                        buffer = &rule->from;
+                                        prefixlen = &rule->from_prefixlen;
                                 }
+
+                                r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
+                                if (r < 0) {
+                                        log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
+                                        continue;
+                                }
+
                         } else if (streq(a, "tos")) {
                                 r = safe_atou8(b, &rule->tos);
                                 if (r < 0) {
@@ -1239,7 +1262,7 @@ void routing_policy_rule_purge(Manager *m, Link *link) {
                 existing = set_get(m->rules_foreign, rule);
                 if (existing) {
 
-                        r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
+                        r = routing_policy_rule_remove(rule, link, NULL);
                         if (r < 0) {
                                 log_warning_errno(r, "Could not remove routing policy rules: %m");
                                 continue;
index 3bb3b4cd8110447e77dc4506541935c8ced98691..b35126e2cfd1a2be7252c73d5cba7709801df35c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "in-addr-util.h"
 #include "conf-parser.h"
+#include "missing_fib_rules.h"
 
 typedef struct RoutingPolicyRule RoutingPolicyRule;
 
@@ -24,6 +25,8 @@ struct RoutingPolicyRule {
         Link *link;
         NetworkConfigSection *section;
 
+        bool invert_rule;
+
         uint8_t tos;
         uint8_t protocol;
 
@@ -53,10 +56,8 @@ void routing_policy_rule_free(RoutingPolicyRule *rule);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(RoutingPolicyRule*, routing_policy_rule_free);
 
-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_configure(RoutingPolicyRule *address, Link *link, link_netlink_message_handler_t callback, bool update);
+int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback);
 
 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, const char *iif, const char *oif, uint8_t protocol, const struct fib_rule_port_range *sport,
@@ -79,4 +80,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_prefix);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_priority);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_device);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_port_range);
-CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_protocol);
+CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_ip_protocol);
+CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_invert);
index 4fa5533c6016af0cf2c33278aef3ac57ac9db016..fcecafe08396ff53eba49be02ead21c4577db0ff 100644 (file)
@@ -4,13 +4,16 @@
 #include "sd-event.h"
 
 #include "capability-util.h"
+#include "daemon-util.h"
+#include "main-func.h"
 #include "mkdir.h"
 #include "networkd-conf.h"
 #include "networkd-manager.h"
 #include "signal-util.h"
 #include "user-util.h"
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
         const char *user = "systemd-network";
         uid_t uid;
@@ -21,17 +24,12 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                r = -EINVAL;
-                goto out;
-        }
+        if (argc != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
 
         r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
-        if (r < 0) {
-                log_error_errno(r, "Cannot resolve user name %s: %m", user);
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Cannot resolve user name %s: %m", user);
 
         /* Create runtime directory. This is not necessary when networkd is
          * started with "RuntimeDirectory=systemd/netif", or after
@@ -49,7 +47,7 @@ int main(int argc, char *argv[]) {
                                     (1ULL << CAP_NET_BROADCAST) |
                                     (1ULL << CAP_NET_RAW));
                 if (r < 0)
-                        goto out;
+                        return log_error_errno(r, "Failed to drop privileges: %m");
         }
 
         /* Always create the directories people can create inotify watches in.
@@ -70,72 +68,50 @@ int main(int argc, char *argv[]) {
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
         r = manager_new(&m);
-        if (r < 0) {
-                log_error_errno(r, "Could not create manager: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not create manager: %m");
 
         r = manager_connect_bus(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not connect to bus: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not connect to bus: %m");
 
         r = manager_parse_config_file(m);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse configuration file: %m");
 
         r = manager_load_config(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not load configuration files: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not load configuration files: %m");
 
         r = manager_rtnl_enumerate_links(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not enumerate links: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate links: %m");
 
         r = manager_rtnl_enumerate_addresses(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not enumerate addresses: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate addresses: %m");
 
         r = manager_rtnl_enumerate_routes(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not enumerate routes: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate routes: %m");
 
         r = manager_rtnl_enumerate_rules(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not enumerate rules: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate rules: %m");
 
         r = manager_start(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not start manager: %m");
-                goto out;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not start manager: %m");
 
         log_info("Enumeration completed");
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
+        notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
 
         r = sd_event_loop(m->event);
-        if (r < 0) {
-                log_error_errno(r, "Event loop failed: %m");
-                goto out;
-        }
-out:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
+        if (r < 0)
+                return log_error_errno(r, "Event loop failed: %m");
 
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index d112471587752eb5966f86186292904d804de581..f80f3c09a90f0b5f1c03165b34ef18c45c4c3d44 100644 (file)
@@ -10,6 +10,7 @@
 #include "networkd-manager.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 
 static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) {
         char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX",
index 7f30862bbfc79134f4c1e1b17c227ce6744625f8..71b6cf6b87774b83f118725b6cc89563b04bc749 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "sd-daemon.h"
 
+#include "daemon-util.h"
+#include "main-func.h"
 #include "manager.h"
 #include "pretty-print.h"
 #include "signal-util.h"
@@ -14,6 +16,9 @@ static usec_t arg_timeout = 120 * USEC_PER_SEC;
 static char **arg_interfaces = NULL;
 static char **arg_ignore = NULL;
 
+STATIC_DESTRUCTOR_REGISTER(arg_interfaces, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
+
 static int help(void) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -105,7 +110,8 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
 
@@ -123,37 +129,24 @@ int main(int argc, char *argv[]) {
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
         r = manager_new(&m, arg_interfaces, arg_ignore, arg_timeout);
-        if (r < 0) {
-                log_error_errno(r, "Could not create manager: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not create manager: %m");
 
-        if (manager_all_configured(m)) {
-                r = 0;
-                goto finish;
-        }
+        if (manager_all_configured(m))
+                goto success;
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Waiting for network connections...");
+        notify_message = notify_start("READY=1\n"
+                                      "STATUS=Waiting for network connections...",
+                                      "STATUS=Failed to wait for network connectivity...");
 
         r = sd_event_loop(m->event);
-        if (r < 0) {
-                log_error_errno(r, "Event loop failed: %m");
-                goto finish;
-        }
-
-finish:
-        strv_free(arg_interfaces);
-        strv_free(arg_ignore);
-
-        if (r >= 0) {
-                sd_notify(false, "STATUS=All interfaces configured...");
+        if (r < 0)
+                return log_error_errno(r, "Event loop failed: %m");
 
-                return EXIT_SUCCESS;
-        } else {
-                sd_notify(false, "STATUS=Failed waiting for network connectivity...");
+success:
+        notify_message = "STATUS=All interfaces configured...";
 
-                return EXIT_FAILURE;
-        }
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index 53c42f0ee478e08a955ee53172dd41c376193c13..97fa092caeee344da448c4ec2eb5c1d42b1d4e90 100644 (file)
@@ -8,6 +8,7 @@
 #include "fs-util.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nspawn-cgroup.h"
 #include "nspawn-mount.h"
 #include "path-util.h"
index 48187079b37735875c39a645ea0abd9b23763b4a..a9af889747b838e730c3b2c4f1526debf02d2c5c 100644 (file)
@@ -6,11 +6,11 @@
 #include "alloc-util.h"
 #include "escape.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "label.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nspawn-mount.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -19,6 +19,7 @@
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -556,6 +557,8 @@ int mount_all(const char *dest,
                   MOUNT_FATAL },
                 { "tmpfs",           "/run",            "tmpfs", "mode=755",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,
                   MOUNT_FATAL },
+                { "mqueue",          "/dev/mqueue",     "mqueue", NULL,       0,
+                  MOUNT_FATAL },
 
 #if HAVE_SELINUX
                 { "/sys/fs/selinux", "/sys/fs/selinux", NULL,    NULL,        MS_BIND,
index 214fa40804c00abba02969cb6ebf7f05bf6a7b0f..9d0f8a9956b3fc47b93728f93915183f397c31da 100644 (file)
@@ -11,6 +11,7 @@
 #include "alloc-util.h"
 #include "ether-addr-util.h"
 #include "lockfile-util.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "nspawn-network.h"
 #include "siphash24.h"
index 4a46a25eac7f94c337b99f94c0c43f23b72138fb..db2f5467b50e81c5ee8837bb3f93d0f4f350d4e9 100644 (file)
@@ -479,10 +479,6 @@ finish:
         return r;
 }
 
-int fd_patch_uid(int fd, uid_t shift, uid_t range) {
-        return fd_patch_uid_internal(fd, false, shift, range);
-}
-
 int path_patch_uid(const char *path, uid_t shift, uid_t range) {
         int fd;
 
index 31d2491234b76b63f5dad17c20c212245b18cadd..b7c6ce2b730d2d87a80397174c9a96085b7f1dce 100644 (file)
@@ -4,5 +4,4 @@
 
 #include <sys/types.h>
 
-int fd_patch_uid(int fd, uid_t shift, uid_t range);
 int path_patch_uid(const char *path, uid_t shift, uid_t range);
index ba83826bbb4582c5a75484adcf38ba56d781f962..a63aa32e909c247c40882b626b8764c3dc3110bf 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "conf-parser.h"
 #include "macro.h"
+#include "missing_resource.h"
 #include "nspawn-expose-ports.h"
 #include "nspawn-mount.h"
 
index e865d5b2a824bcc518d298d86e7748ef3bbb83bb..86fd9deec0fee11dd533d8a45589fd977639eabd 100644 (file)
@@ -12,6 +12,7 @@
 #include "mkdir.h"
 #include "nspawn-setuid.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -44,6 +45,8 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
 
                 close_all_fds(NULL, 0);
 
+                (void) rlimit_nofile_safe();
+
                 execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
                 execle("/bin/getent", "getent", database, key, NULL, &empty_env);
                 _exit(EXIT_FAILURE);
index 6eddae49d993cf6dec0d5d1528bbec18913006c5..03538d1c2f384846fb72d27f13cffc9e5385c4a5 100644 (file)
@@ -6,6 +6,7 @@
 #include <errno.h>
 #include <getopt.h>
 #include <grp.h>
+#include <linux/fs.h>
 #include <linux/loop.h>
 #include <pwd.h>
 #include <sched.h>
@@ -17,7 +18,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/file.h>
-#include <sys/mount.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
 #include <sys/types.h>
@@ -60,6 +60,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "netlink-util.h"
 #include "nspawn-cgroup.h"
 #include "nspawn-def.h"
@@ -92,6 +93,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "umask-util.h"
 #include "user-util.h"
 #include "util.h"
index 8e04eb3c23c72bcae15f4bc915360e38957ff401..c9d1c27792e2071f3b62cf5b49f4edf0b87208a8 100644 (file)
 #include "format-util.h"
 #include "log.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
+#include "stat-util.h"
 #include "strv.h"
 
 static const char *arg_target = NULL;
@@ -69,13 +70,16 @@ static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numbl
 
 #if HAVE_LIBCRYPTSETUP
 static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
-        char devpath[DEV_NUM_PATH_MAX], main_devpath[DEV_NUM_PATH_MAX];
-        _cleanup_close_ int main_devfd = -1;
+        _cleanup_free_ char *devpath = NULL, *main_devpath = NULL;
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+        _cleanup_close_ int main_devfd = -1;
         uint64_t size;
         int r;
 
-        xsprintf_dev_num_path(main_devpath, "block", main_devno);
+        r = device_path_make_major_minor(S_IFBLK, main_devno, &main_devpath);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format device major/minor path: %m");
+
         main_devfd = open(main_devpath, O_RDONLY|O_CLOEXEC);
         if (main_devfd < 0)
                 return log_error_errno(errno, "Failed to open \"%s\": %m", main_devpath);
@@ -85,8 +89,10 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
                                        main_devpath);
 
         log_debug("%s is %"PRIu64" bytes", main_devpath, size);
+        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format major/minor path: %m");
 
-        xsprintf_dev_num_path(devpath, "block", devno);
         r = crypt_init(&cd, devpath);
         if (r < 0)
                 return log_error_errno(r, "crypt_init(\"%s\") failed: %m", devpath);
@@ -115,9 +121,8 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
 #endif
 
 static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
+        _cleanup_free_ char *fstype = NULL, *devpath = NULL;
         dev_t devno;
-        char devpath[DEV_NUM_PATH_MAX];
-        _cleanup_free_ char *fstype = NULL;
         int r;
 
 #if HAVE_LIBCRYPTSETUP
@@ -137,7 +142,10 @@ static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
         if (devno == main_devno)
                 return 0;
 
-        xsprintf_dev_num_path(devpath, "block", devno);
+        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format device major/minor path: %m");
+
         r = probe_filesystem(devpath, &fstype);
         if (r == -EUCLEAN)
                 return log_warning_errno(r, "Cannot reliably determine probe \"%s\", refusing to proceed.", devpath);
@@ -222,12 +230,13 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        dev_t devno;
         _cleanup_close_ int mountfd = -1, devfd = -1;
-        int blocksize;
+        _cleanup_free_ char *devpath = NULL;
         uint64_t size, numblocks;
-        char devpath[DEV_NUM_PATH_MAX], fb[FORMAT_BYTES_MAX];
+        char fb[FORMAT_BYTES_MAX];
         struct statfs sfs;
+        dev_t devno;
+        int blocksize;
         int r;
 
         log_setup_service();
@@ -264,7 +273,12 @@ int main(int argc, char *argv[]) {
                 return EXIT_FAILURE;
         }
 
-        xsprintf_dev_num_path(devpath, "block", devno);
+        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        if (r < 0) {
+                log_error_errno(r, "Failed to format device major/minor path: %m");
+                return EXIT_FAILURE;
+        }
+
         devfd = open(devpath, O_RDONLY|O_CLOEXEC);
         if (devfd < 0) {
                 log_error_errno(errno, "Failed to open \"%s\": %m", devpath);
index 88834092bde332cdeebc781c419e7f719cbd2ec5..0b9bae55e7b3435d3416a35b9b764b8908b0ac2d 100644 (file)
@@ -28,7 +28,7 @@ static int makefs(const char *type, const char *device) {
         if (access(mkfs, X_OK) != 0)
                 return log_error_errno(errno, "%s is not executable: %m", mkfs);
 
-        r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+        r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
index ca8043b41eeca0da4821fd34c4358061812c3807..5b62486ea9eb023409c11c0219ea717f1a2ddefe 100644 (file)
@@ -26,6 +26,7 @@
 #include "socket-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 
 static const char profile_dirs[] = CONF_PATHS_NULSTR("systemd/portable/profile");
@@ -92,21 +93,6 @@ PortableMetadata *portable_metadata_unref(PortableMetadata *i) {
         return mfree(i);
 }
 
-Hashmap *portable_metadata_hashmap_unref(Hashmap *h) {
-
-        for (;;) {
-                PortableMetadata *i;
-
-                i = hashmap_steal_first(h);
-                if (!i)
-                        break;
-
-                portable_metadata_unref(i);
-        }
-
-        return hashmap_free(h);
-}
-
 static int compare_metadata(PortableMetadata *const *x, PortableMetadata *const *y) {
         return strcmp((*x)->name, (*y)->name);
 }
@@ -232,6 +218,9 @@ static int recv_item(
         return 0;
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char, string_hash_func, string_compare_func,
+                                              PortableMetadata, portable_metadata_unref);
+
 static int extract_now(
                 const char *where,
                 char **matches,
@@ -239,7 +228,7 @@ static int extract_now(
                 PortableMetadata **ret_os_release,
                 Hashmap **ret_unit_files) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_close_ int os_release_fd = -1;
@@ -286,7 +275,7 @@ static int extract_now(
         if (r < 0)
                 return log_debug_errno(r, "Failed to acquire lookup paths: %m");
 
-        unit_files = hashmap_new(&string_hash_ops);
+        unit_files = hashmap_new(&portable_metadata_hash_ops);
         if (!unit_files)
                 return -ENOMEM;
 
@@ -362,7 +351,7 @@ static int portable_extract_by_path(
                 Hashmap **ret_unit_files,
                 sd_bus_error *error) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata* os_release = NULL;
         _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
         int r;
@@ -432,7 +421,7 @@ static int portable_extract_by_path(
 
                 seq[1] = safe_close(seq[1]);
 
-                unit_files = hashmap_new(&string_hash_ops);
+                unit_files = hashmap_new(&portable_metadata_hash_ops);
                 if (!unit_files)
                         return -ENOMEM;
 
@@ -986,7 +975,7 @@ int portable_attach(
                 size_t *n_changes,
                 sd_bus_error *error) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(image_unrefp) Image *image = NULL;
         PortableMetadata *item;
index 9fbf61265a054f184440c2d1a4bc506eb553313c..ad81b584a5765bd7be3939006d084428a5b45c51 100644 (file)
@@ -54,9 +54,6 @@ typedef struct PortableChange {
 PortableMetadata *portable_metadata_unref(PortableMetadata *i);
 DEFINE_TRIVIAL_CLEANUP_FUNC(PortableMetadata*, portable_metadata_unref);
 
-Hashmap *portable_metadata_hashmap_unref(Hashmap *h);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, portable_metadata_hashmap_unref);
-
 int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret);
 
 int portable_extract(const char *image, char **matches, PortableMetadata **ret_os_release, Hashmap **ret_unit_files, sd_bus_error *error);
index 9af9744fd038541b0036831eb7d8c15e674bc578..4763c0d7d06bd105d2fe502dee84f633eb987645 100644 (file)
@@ -10,8 +10,8 @@
 #include "bus-util.h"
 #include "def.h"
 #include "dirent-util.h"
+#include "env-file.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-table.h"
 #include "fs-util.h"
 #include "locale-util.h"
@@ -500,7 +500,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));
 
-        table = table_new("NAME", "TYPE", "RO", "CRTIME", "MTIME", "USAGE", "STATE");
+        table = table_new("name", "type", "ro", "crtime", "mtime", "usage", "state");
         if (!table)
                 return log_oom();
 
index 70fc750fe3e6b2ad8048dd00c2d994a1f9f368a7..3cbdb0b0cc22ded9660717fa1776ba851453e51f 100644 (file)
@@ -7,6 +7,7 @@
 #include "fd-util.h"
 #include "io-util.h"
 #include "machine-image.h"
+#include "missing_capability.h"
 #include "portable.h"
 #include "portabled-bus.h"
 #include "portabled-image-bus.h"
@@ -131,7 +132,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro
 
 static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        _cleanup_hashmap_free_ Hashmap *images = NULL;
         Manager *m = userdata;
         Image *image;
         Iterator i;
@@ -140,7 +141,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
         assert(message);
         assert(m);
 
-        images = hashmap_new(&string_hash_ops);
+        images = hashmap_new(&image_hash_ops);
         if (!images)
                 return -ENOMEM;
 
index 0e1f7c5e87d0a73227e6fb51b324ff3c986a0ae8..1e618175c72b24299e0c351578d320f9ab4e1f12 100644 (file)
@@ -8,6 +8,7 @@
 #include "fileio.h"
 #include "io-util.h"
 #include "machine-image.h"
+#include "missing_capability.h"
 #include "portable.h"
 #include "portabled-bus.h"
 #include "portabled-image-bus.h"
@@ -93,7 +94,7 @@ int bus_image_common_get_metadata(
                 sd_bus_error *error) {
 
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ PortableMetadata **sorted = NULL;
         _cleanup_strv_free_ char **matches = NULL;
@@ -693,7 +694,7 @@ not_found:
 }
 
 int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        _cleanup_hashmap_free_ Hashmap *images = NULL;
         _cleanup_strv_free_ char **l = NULL;
         size_t n_allocated = 0, n = 0;
         Manager *m = userdata;
@@ -705,7 +706,7 @@ int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, cha
         assert(path);
         assert(nodes);
 
-        images = hashmap_new(&string_hash_ops);
+        images = hashmap_new(&image_hash_ops);
         if (!images)
                 return -ENOMEM;
 
index a6b3f52e99a269266b48e33b6fac153c65590aac..d95845b32a0f6354547525cc0e200020ea810ac4 100644 (file)
@@ -16,7 +16,7 @@ static int image_cache_flush(sd_event_source *s, void *userdata) {
         assert(s);
         assert(m);
 
-        hashmap_clear_with_destructor(m->image_cache, image_unref);
+        hashmap_clear(m->image_cache);
         return 0;
 }
 
@@ -25,7 +25,7 @@ static int manager_image_cache_initialize(Manager *m) {
 
         assert(m);
 
-        r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
+        r = hashmap_ensure_allocated(&m->image_cache, &image_hash_ops);
         if (r < 0)
                 return r;
 
index cfaf2a59e3ece38f56a012d775f15a65f0a45d51..63fc34046913c5b9d7a12189c0e75cc4d15eb715 100644 (file)
@@ -47,7 +47,7 @@ static int manager_new(Manager **ret) {
 static Manager* manager_unref(Manager *m) {
         assert(m);
 
-        hashmap_free_with_destructor(m->image_cache, image_unref);
+        hashmap_free(m->image_cache);
 
         sd_event_source_unref(m->image_cache_defer_event);
 
index a51a76411e7c56893fee49d91bfa7e30621ebaf6..90f542a058c4928f5df35c72595882a33e1f2fc9 100644 (file)
@@ -78,7 +78,7 @@ static int run(int argc, char *argv[]) {
                         return 0;
         }
 
-        r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
+        r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_WAIT|FORK_LOG, NULL);
         if (r < 0)
                 return r;
         if (r == 0) {
index 11f18b1173deb6fbcfc31b52d06540be3982dcd8..cd5510bf12a7d64abc85097623d159b5d473345e 100644 (file)
@@ -21,7 +21,6 @@ static const char *arg_dest = "/tmp";
 
 static int add_symlink(const char *service, const char *where) {
         const char *from, *to;
-        int r;
 
         assert(service);
         assert(where);
@@ -31,8 +30,7 @@ static int add_symlink(const char *service, const char *where) {
 
         (void) mkdir_parents_label(to, 0755);
 
-        r = symlink(from, to);
-        if (r < 0) {
+        if (symlink(from, to) < 0) {
                 if (errno == EEXIST)
                         return 0;
 
@@ -42,6 +40,21 @@ static int add_symlink(const char *service, const char *where) {
         return 1;
 }
 
+static int check_executable(const char *path) {
+        assert(path);
+
+        if (access(path, X_OK) < 0) {
+                if (errno == ENOENT)
+                        return log_debug_errno(errno, "%s does not exist, skipping.", path);
+                if (errno == EACCES)
+                        return log_info_errno(errno, "%s is not marked executable, skipping.", path);
+
+                return log_warning_errno(errno, "Couldn't determine if %s exists and is executable, skipping: %m", path);
+        }
+
+        return 0;
+}
+
 static int run(int argc, char *argv[]) {
         int r = 0, k = 0;
 
@@ -53,19 +66,13 @@ static int run(int argc, char *argv[]) {
         if (argc > 1)
                 arg_dest = argv[1];
 
-        if (access(RC_LOCAL_SCRIPT_PATH_START, X_OK) < 0)
-                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
-                               RC_LOCAL_SCRIPT_PATH_START " is not executable: %m");
-        else {
+        if (check_executable(RC_LOCAL_SCRIPT_PATH_START) >= 0) {
                 log_debug("Automatically adding rc-local.service.");
 
                 r = add_symlink("rc-local.service", "multi-user.target");
         }
 
-        if (access(RC_LOCAL_SCRIPT_PATH_STOP, X_OK) < 0)
-                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
-                               RC_LOCAL_SCRIPT_PATH_STOP " is not executable: %m");
-        else {
+        if (check_executable(RC_LOCAL_SCRIPT_PATH_STOP) >= 0) {
                 log_debug("Automatically adding halt-local.service.");
 
                 k = add_symlink("halt-local.service", "final.target");
index 28edbbd856cba1d8fcec727d7f8bc508cc234188..af92ddb96cf5499a22c5a1692d0a9bf6cb7f11c1 100644 (file)
@@ -62,7 +62,7 @@ static int run(int argc, char *argv[]) {
 
                 log_debug("Remounting %s", me->mnt_dir);
 
-                r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+                r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
                 if (r < 0)
                         return r;
                 if (r == 0) {
index 242c26e5caee869c00233206dda19e73b8e18579..383d0b819bdb08e7f017ce8277d72128950d873a 100644 (file)
@@ -212,7 +212,7 @@ int resolvconf_parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Expected interface name as argument.");
 
-        r = ifname_mangle(argv[optind], false);
+        r = ifname_mangle(argv[optind]);
         if (r <= 0)
                 return r;
 
index 5f42c6d021ca6710afc04d234b3282a54e220a92..8a175ebefc7247a55c9cf2679da64b7776643122 100644 (file)
@@ -16,6 +16,7 @@
 #include "gcrypt-util.h"
 #include "in-addr-util.h"
 #include "main-func.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "pager.h"
 #include "parse-util.h"
@@ -87,39 +88,26 @@ static int parse_ifindex_and_warn(const char *s) {
         return ifi;
 }
 
-int ifname_mangle(const char *s, bool allow_loopback) {
+int ifname_mangle(const char *s) {
         _cleanup_free_ char *iface = NULL;
         const char *dot;
-        int r;
+        int ifi;
 
         assert(s);
 
-        if (arg_ifname) {
-                assert(arg_ifindex >= 0);
-
-                if (!allow_loopback && arg_ifindex == LOOPBACK_IFINDEX)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "Interface can't be the loopback interface (lo). Sorry.");
-
-                return 1;
-        }
-
         dot = strchr(s, '.');
         if (dot) {
+                log_debug("Ignoring protocol specifier '%s'.", dot + 1);
                 iface = strndup(s, dot - s);
-                if (!iface)
-                        return log_oom();
 
-                log_debug("Ignoring protocol specifier '%s'.", dot + 1);
-        } else {
+        } else
                 iface = strdup(s);
-                if (!iface)
-                        return log_oom();
-        }
+        if (!iface)
+                return log_oom();
 
-        if (parse_ifindex(iface, &r) < 0) {
-                r = if_nametoindex(iface);
-                if (r <= 0) {
+        if (parse_ifindex(iface, &ifi) < 0) {
+                ifi = if_nametoindex(iface);
+                if (ifi <= 0) {
                         if (errno == ENODEV && arg_ifindex_permissive) {
                                 log_debug("Interface '%s' not found, but -f specified, ignoring.", iface);
                                 return 0; /* done */
@@ -129,12 +117,13 @@ int ifname_mangle(const char *s, bool allow_loopback) {
                 }
         }
 
-        if (!allow_loopback && r == LOOPBACK_IFINDEX)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Interface can't be the loopback interface (lo). Sorry.");
+        if (arg_ifindex > 0 && arg_ifindex != ifi) {
+                log_error("Specified multiple different interfaces. Refusing.");
+                return -EINVAL;
+        }
 
-        arg_ifindex = r;
-        arg_ifname = TAKE_PTR(iface);
+        arg_ifindex = ifi;
+        free_and_replace(arg_ifname, iface);
 
         return 1;
 }
@@ -148,7 +137,7 @@ static void print_source(uint64_t flags, usec_t rtt) {
         if (flags == 0)
                 return;
 
-        fputs("\n-- Information acquired via", stdout);
+        printf("\n%s-- Information acquired via", ansi_grey());
 
         if (flags != 0)
                 printf(" protocol%s%s%s%s%s",
@@ -160,12 +149,24 @@ static void print_source(uint64_t flags, usec_t rtt) {
 
         assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
 
-        printf(" in %s", rtt_str);
+        printf(" in %s.%s\n"
+               "%s-- Data is authenticated: %s%s\n",
+               rtt_str, ansi_normal(),
+               ansi_grey(), yes_no(flags & SD_RESOLVED_AUTHENTICATED), ansi_normal());
+}
+
+static void print_ifindex_comment(int printed_so_far, int ifindex) {
+        char ifname[IF_NAMESIZE];
 
-        fputc('.', stdout);
-        fputc('\n', stdout);
+        if (ifindex <= 0)
+                return;
 
-        printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
+        if (!if_indextoname(ifindex, ifname))
+                log_warning_errno(errno, "Failed to resolve interface name for index %i, ignoring: %m", ifindex);
+        else
+                printf("%*s%s-- link: %s%s",
+                       60 > printed_so_far ? 60 - printed_so_far : 0, " ", /* Align comment to the 60th column */
+                       ansi_grey(), ifname, ansi_normal());
 }
 
 static int resolve_host(sd_bus *bus, const char *name) {
@@ -209,8 +210,7 @@ static int resolve_host(sd_bus *bus, const char *name) {
 
         while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
                 _cleanup_free_ char *pretty = NULL;
-                char ifname[IF_NAMESIZE] = "";
-                int ifindex, family;
+                int ifindex, family, k;
                 const void *a;
                 size_t sz;
 
@@ -238,17 +238,16 @@ static int resolve_host(sd_bus *bus, const char *name) {
                         return -EINVAL;
                 }
 
-                if (ifindex > 0 && !if_indextoname(ifindex, ifname))
-                        log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
                 r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
                 if (r < 0)
                         return log_error_errno(r, "Failed to print address for %s: %m", name);
 
-                printf("%*s%s %s%s%s\n",
-                       (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
-                       pretty,
-                       isempty(ifname) ? "" : "%", ifname);
+                k = printf("%*s%s %s%s%s",
+                           (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
+                           ansi_highlight(), pretty, ansi_normal());
+
+                print_ifindex_comment(k, ifindex);
+                fputc('\n', stdout);
 
                 c++;
         }
@@ -282,7 +281,6 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_free_ char *pretty = NULL;
-        char ifname[IF_NAMESIZE] = "";
         uint64_t flags;
         unsigned c = 0;
         usec_t ts;
@@ -299,10 +297,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
         if (r < 0)
                 return log_oom();
 
-        if (ifindex > 0 && !if_indextoname(ifindex, ifname))
-                return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
-        log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
+        log_debug("Resolving %s.", pretty);
 
         r = sd_bus_message_new_method_call(
                         bus,
@@ -340,6 +335,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
 
         while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
                 const char *n;
+                int k;
 
                 assert_cc(sizeof(int) == sizeof(int32_t));
 
@@ -351,16 +347,13 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
                 if (r < 0)
                         return r;
 
-                ifname[0] = 0;
-                if (ifindex > 0 && !if_indextoname(ifindex, ifname))
-                        log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+                k = printf("%*s%s %s%s%s",
+                           (int) strlen(pretty), c == 0 ? pretty : "",
+                           c == 0 ? ":" : " ",
+                           ansi_highlight(), n, ansi_normal());
 
-                printf("%*s%*s%*s%s %s\n",
-                       (int) strlen(pretty), c == 0 ? pretty : "",
-                       isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
-                       (int) strlen(ifname), c == 0 ? ifname : "",
-                       c == 0 ? ":" : " ",
-                       n);
+                print_ifindex_comment(k, ifindex);
+                fputc('\n', stdout);
 
                 c++;
         }
@@ -389,7 +382,6 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
         int r;
-        char ifname[IF_NAMESIZE] = "";
 
         r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
         if (r < 0)
@@ -415,15 +407,15 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
                 fwrite(data, 1, k, stdout);
         } else {
                 const char *s;
+                int k;
 
                 s = dns_resource_record_to_string(rr);
                 if (!s)
                         return log_oom();
 
-                if (ifindex > 0 && !if_indextoname(ifindex, ifname))
-                        log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
-                printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
+                k = printf("%s", s);
+                print_ifindex_comment(k, ifindex);
+                fputc('\n', stdout);
         }
 
         return 0;
@@ -767,8 +759,7 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
 
                 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
                         _cleanup_free_ char *pretty = NULL;
-                        char ifname[IF_NAMESIZE] = "";
-                        int ifindex, family;
+                        int ifindex, family, k;
                         const void *a;
 
                         assert_cc(sizeof(int) == sizeof(int32_t));
@@ -795,14 +786,13 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
                                 return -EINVAL;
                         }
 
-                        if (ifindex > 0 && !if_indextoname(ifindex, ifname))
-                                log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
-                        r = in_addr_to_string(family, a, &pretty);
+                        r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to print address for %s: %m", name);
 
-                        printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
+                        k = printf("%*s%s", (int) indent, "", pretty);
+                        print_ifindex_comment(k, ifindex);
+                        fputc('\n', stdout);
                 }
                 if (r < 0)
                         return bus_log_parse_error(r);
@@ -1873,14 +1863,16 @@ static int verb_dns(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_DNS);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_DNS);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
 
         r = sd_bus_message_new_method_call(
@@ -1957,14 +1949,16 @@ static int verb_domain(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_DOMAIN);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_DOMAIN);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL);
 
         r = sd_bus_message_new_method_call(
@@ -2033,14 +2027,16 @@ static int verb_llmnr(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_LLMNR);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_LLMNR);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
 
         r = sd_bus_call_method(bus,
@@ -2072,14 +2068,16 @@ static int verb_mdns(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_MDNS);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_MDNS);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
 
         r = sd_bus_call_method(bus,
@@ -2111,14 +2109,16 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_PRIVATE);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_PRIVATE);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL);
 
         r = sd_bus_call_method(bus,
@@ -2150,14 +2150,16 @@ static int verb_dnssec(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_DNSSEC);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_DNSSEC);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL);
 
         r = sd_bus_call_method(bus,
@@ -2192,14 +2194,16 @@ static int verb_nta(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        if (argc <= 1)
-                return status_all(bus, STATUS_NTA);
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (arg_ifindex <= 0)
+                return status_all(bus, STATUS_NTA);
 
-        if (argc == 2)
+        if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_NTA, NULL);
 
         /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
@@ -2257,9 +2261,14 @@ static int verb_revert_link(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        r = ifname_mangle(argv[1], false);
-        if (r < 0)
-                return r;
+        if (argc >= 2) {
+                r = ifname_mangle(argv[1]);
+                if (r < 0)
+                        return r;
+        }
+
+        if (arg_ifindex <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required.");
 
         r = sd_bus_call_method(bus,
                                "org.freedesktop.resolve1",
@@ -2500,8 +2509,7 @@ static int compat_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case 'i':
-                        arg_ifname = mfree(arg_ifname);
-                        r = ifname_mangle(optarg, true);
+                        r = ifname_mangle(optarg);
                         if (r < 0)
                                 return r;
                         break;
@@ -2731,10 +2739,6 @@ static int compat_parse_argv(int argc, char *argv[]) {
                 if (arg_ifindex <= 0)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
-
-                if (arg_ifindex == LOOPBACK_IFINDEX)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "Interface can't be the loopback interface (lo). Sorry.");
         }
 
         return 1 /* work to do */;
@@ -2792,8 +2796,7 @@ static int native_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case 'i':
-                        arg_ifname = mfree(arg_ifname);
-                        r = ifname_mangle(optarg, true);
+                        r = ifname_mangle(optarg);
                         if (r < 0)
                                 return r;
                         break;
@@ -2952,7 +2955,7 @@ static int native_main(int argc, char *argv[], sd_bus *bus) {
                 { "dnsovertls",            VERB_ANY, 3,        0,            verb_dns_over_tls      },
                 { "dnssec",                VERB_ANY, 3,        0,            verb_dnssec           },
                 { "nta",                   VERB_ANY, VERB_ANY, 0,            verb_nta              },
-                { "revert",                2,        2,        0,            verb_revert_link      },
+                { "revert",                VERB_ANY, 2,        0,            verb_revert_link      },
                 {}
         };
 
index 7858fcd6b42dc1fe96bc2ddebd4d6c3891b88cdc..6b3a1f844515f49739b2ccda31d041e87e1e8755 100644 (file)
@@ -26,4 +26,4 @@ extern char **arg_set_dns;
 extern char **arg_set_domain;
 extern bool arg_ifindex_permissive;
 
-int ifname_mangle(const char *s, bool allow_loopback);
+int ifname_mangle(const char *s);
index 75702d593f41a607c759f38b056400f13cb76f15..fbe823da66c70a40a394715a09b7558f0c4d7061 100644 (file)
@@ -4,6 +4,7 @@
 #include "bus-common-errors.h"
 #include "bus-util.h"
 #include "dns-domain.h"
+#include "missing_capability.h"
 #include "resolved-bus.h"
 #include "resolved-def.h"
 #include "resolved-dns-synthesize.h"
@@ -191,7 +192,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
 
         /* The key names are not necessarily normalized, make sure that they are when we return them to our bus
          * clients. */
-        r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+        r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
         if (r < 0)
                 goto finish;
 
@@ -404,7 +405,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
                 if (r == 0)
                         continue;
 
-                r = dns_name_normalize(rr->ptr.name, &normalized);
+                r = dns_name_normalize(rr->ptr.name, 0, &normalized);
                 if (r < 0)
                         goto finish;
 
@@ -742,7 +743,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
         if (r < 0)
                 return r;
 
-        r = dns_name_normalize(rr->srv.name, &normalized);
+        r = dns_name_normalize(rr->srv.name, 0, &normalized);
         if (r < 0)
                 return r;
 
@@ -798,7 +799,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
         if (canonical) {
                 normalized = mfree(normalized);
 
-                r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+                r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
                 if (r < 0)
                         return r;
         }
index 6767dca302047aefcc958edbbafe2d0326e452f6..d7252d3dac133ac287d679c5ca133dcfa07cc6dd 100644 (file)
@@ -211,70 +211,6 @@ int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags
         return found;
 }
 
-int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *ret_flags) {
-        DnsAnswerFlags flags = 0, i_flags;
-        DnsResourceRecord *i;
-        bool found = false;
-        int r;
-
-        assert(rr);
-
-        DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
-                r = dns_resource_record_equal(i, rr);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        continue;
-
-                if (!ret_flags)
-                        return 1;
-
-                if (found)
-                        flags &= i_flags;
-                else {
-                        flags = i_flags;
-                        found = true;
-                }
-        }
-
-        if (ret_flags)
-                *ret_flags = flags;
-
-        return found;
-}
-
-int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
-        DnsAnswerFlags flags = 0, i_flags;
-        DnsResourceRecord *i;
-        bool found = false;
-        int r;
-
-        assert(key);
-
-        DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
-                r = dns_resource_key_equal(i->key, key);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        continue;
-
-                if (!ret_flags)
-                        return true;
-
-                if (found)
-                        flags &= i_flags;
-                else {
-                        flags = i_flags;
-                        found = true;
-                }
-        }
-
-        if (ret_flags)
-                *ret_flags = flags;
-
-        return found;
-}
-
 int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
         DnsResourceRecord *i;
 
index 9ce7d62773c5a2b3b6e686afdf153219bd546695..97514c34089f4cbb09f206d965b37752c0451a07 100644 (file)
@@ -43,8 +43,6 @@ int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, Dns
 int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex);
 
 int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags);
-int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *combined_flags);
-int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags);
 int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a);
 int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone);
 
index 13da4e5991695cf9f896ae45f0e14bd5721ddb53..d9633629e85c4c712aa903f87ad1a15c4b1e2b27 100644 (file)
@@ -74,7 +74,7 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
                 return -ENOBUFS;
 
         for (;;) {
-                r = dns_label_unescape(&n, buffer, buffer_max);
+                r = dns_label_unescape(&n, buffer, buffer_max, 0);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1705,7 +1705,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
                 return 0;
 
         n = dns_resource_key_name(rr->key);
-        r = dns_label_unescape(&n, label, sizeof(label));
+        r = dns_label_unescape(&n, label, sizeof label, 0);
         if (r <= 0)
                 return r;
         if (r != 1 || label[0] != '*')
@@ -1827,13 +1827,13 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
                 return r;
         if (r > 0)  /* If the name we are interested in is a child of the NSEC RR, then append the asterisk to the NSEC
                      * RR's name. */
-                r = dns_name_concat("*", dns_resource_key_name(rr->key), &wc);
+                r = dns_name_concat("*", dns_resource_key_name(rr->key), 0, &wc);
         else {
                 r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
                 if (r < 0)
                         return r;
 
-                r = dns_name_concat("*", common_suffix, &wc);
+                r = dns_name_concat("*", common_suffix, 0, &wc);
         }
         if (r < 0)
                 return r;
index 6eb12f8ae5e7e110c8d46aa5d80deac91a831058..572271be95c37c8ebd1338eb4f52bd88bb4043a0 100644 (file)
@@ -535,7 +535,7 @@ int dns_packet_append_name(
                         }
                 }
 
-                r = dns_label_unescape(&name, label, sizeof(label));
+                r = dns_label_unescape(&name, label, sizeof label, 0);
                 if (r < 0)
                         goto fail;
 
@@ -2330,17 +2330,14 @@ int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
         return dns_resource_key_equal(p->question->keys[0], key);
 }
 
-static void dns_packet_hash_func(const void *p, struct siphash *state) {
-        const DnsPacket *s = p;
-
+static void dns_packet_hash_func(const DnsPacket *s, struct siphash *state) {
         assert(s);
 
         siphash24_compress(&s->size, sizeof(s->size), state);
         siphash24_compress(DNS_PACKET_DATA((DnsPacket*) s), s->size, state);
 }
 
-static int dns_packet_compare_func(const void *a, const void *b) {
-        const DnsPacket *x = a, *y = b;
+static int dns_packet_compare_func(const DnsPacket *x, const DnsPacket *y) {
         int r;
 
         r = CMP(x->size, y->size);
@@ -2350,10 +2347,7 @@ static int dns_packet_compare_func(const void *a, const void *b) {
         return memcmp(DNS_PACKET_DATA((DnsPacket*) x), DNS_PACKET_DATA((DnsPacket*) y), x->size);
 }
 
-const struct hash_ops dns_packet_hash_ops = {
-        .hash = dns_packet_hash_func,
-        .compare = dns_packet_compare_func
-};
+DEFINE_HASH_OPS(dns_packet_hash_ops, DnsPacket, dns_packet_hash_func, dns_packet_compare_func);
 
 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
         [DNS_RCODE_SUCCESS] = "SUCCESS",
index 67565d267e024b96518a5c1969d30fda45e572fa..a1dffb08a3a28754e5819cac7eb73d020a6a09eb 100644 (file)
@@ -77,7 +77,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
                 return 0;
         }
 
-        r = dns_name_concat(dns_resource_key_name(key), name, &joined);
+        r = dns_name_concat(dns_resource_key_name(key), name, 0, &joined);
         if (r < 0)
                 return r;
 
@@ -222,7 +222,7 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr,
         if (search_domain) {
                 _cleanup_free_ char *joined = NULL;
 
-                r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
+                r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
                 if (r < 0)
                         return r;
 
@@ -254,7 +254,7 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
         if (search_domain) {
                 _cleanup_free_ char *joined = NULL;
 
-                r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
+                r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
                 if (r < 0)
                         return r;
 
@@ -282,9 +282,7 @@ int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *
         return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa));
 }
 
-static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
-        const DnsResourceKey *k = i;
-
+static void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash *state) {
         assert(k);
 
         dns_name_hash_func(dns_resource_key_name(k), state);
@@ -292,8 +290,7 @@ static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
         siphash24_compress(&k->type, sizeof(k->type), state);
 }
 
-static int dns_resource_key_compare_func(const void *a, const void *b) {
-        const DnsResourceKey *x = a, *y = b;
+static int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y) {
         int ret;
 
         ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y));
@@ -311,10 +308,7 @@ static int dns_resource_key_compare_func(const void *a, const void *b) {
         return 0;
 }
 
-const struct hash_ops dns_resource_key_hash_ops = {
-        .hash = dns_resource_key_hash_func,
-        .compare = dns_resource_key_compare_func
-};
+DEFINE_HASH_OPS(dns_resource_key_hash_ops, DnsResourceKey, dns_resource_key_hash_func, dns_resource_key_compare_func);
 
 char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) {
         const char *c, *t;
@@ -1343,9 +1337,7 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
         return !r;
 }
 
-void dns_resource_record_hash_func(const void *i, struct siphash *state) {
-        const DnsResourceRecord *rr = i;
-
+void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *state) {
         assert(rr);
 
         dns_resource_key_hash_func(rr->key, state);
@@ -1486,13 +1478,12 @@ void dns_resource_record_hash_func(const void *i, struct siphash *state) {
         }
 }
 
-static int dns_resource_record_compare_func(const void *a, const void *b) {
-        const DnsResourceRecord *x = a, *y = b;
-        int ret;
+static int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y) {
+        int r;
 
-        ret = dns_resource_key_compare_func(x->key, y->key);
-        if (ret != 0)
-                return ret;
+        r = dns_resource_key_compare_func(x->key, y->key);
+        if (r != 0)
+                return r;
 
         if (dns_resource_record_equal(x, y))
                 return 0;
@@ -1502,10 +1493,7 @@ static int dns_resource_record_compare_func(const void *a, const void *b) {
         return CMP(x, y);
 }
 
-const struct hash_ops dns_resource_record_hash_ops = {
-        .hash = dns_resource_record_hash_func,
-        .compare = dns_resource_record_compare_func,
-};
+DEFINE_HASH_OPS(dns_resource_record_hash_ops, DnsResourceRecord, dns_resource_record_hash_func, dns_resource_record_compare_func);
 
 DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) {
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *copy = NULL;
index d5e74e49378a7b507f6fbc1601035809a7f0bfe2..e02fa2d53b1a4c40d93b49715a4b6e81e7574df1 100644 (file)
@@ -326,7 +326,7 @@ bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b);
 DnsTxtItem *dns_txt_item_copy(DnsTxtItem *i);
 int dns_txt_item_new_empty(DnsTxtItem **ret);
 
-void dns_resource_record_hash_func(const void *i, struct siphash *state);
+void dns_resource_record_hash_func(const DnsResourceRecord *i, struct siphash *state);
 
 extern const struct hash_ops dns_resource_key_hash_ops;
 extern const struct hash_ops dns_resource_record_hash_ops;
index ee204435b33964e2759253d69e43de32dec32803..35c3804dbabc98583ce7d42564a68a8f638c0375 100644 (file)
@@ -413,9 +413,25 @@ static int dns_scope_socket(
 
         if (type == SOCK_DGRAM) {
                 /* Set IP_RECVERR or IPV6_RECVERR to get ICMP error feedback. See discussion in #10345. */
-                r = setsockopt_int(fd, SOL_IP, sa.sa.sa_family == AF_INET ? IP_RECVERR : IPV6_RECVERR, true);
-                if (r < 0)
-                        return r;
+
+                if (sa.sa.sa_family == AF_INET) {
+                        r = setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, true);
+                        if (r < 0)
+                                return r;
+
+                        r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
+                        if (r < 0)
+                                return r;
+
+                } else if (sa.sa.sa_family == AF_INET6) {
+                        r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, true);
+                        if (r < 0)
+                                return r;
+
+                        r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, true);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         if (ret_socket_address)
index 368ec4da19d5edae01dc13345a7ef5c885ae3b5e..21c2442c516b7698a765bf6aec6f67fcefc6826e 100644 (file)
@@ -19,7 +19,7 @@ int dns_search_domain_new(
         assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
         assert(name);
 
-        r = dns_name_normalize(name, &normalized);
+        r = dns_name_normalize(name, 0, &normalized);
         if (r < 0)
                 return r;
 
index be0ae7a731b353d1cbebf2c54a9c5e853a11328a..3e69741b8809bb71776af87da558684d76eaf870 100644 (file)
@@ -43,16 +43,18 @@ int dns_server_new(
                         return -E2BIG;
         }
 
-        s = new0(DnsServer, 1);
+        s = new(DnsServer, 1);
         if (!s)
                 return -ENOMEM;
 
-        s->n_ref = 1;
-        s->manager = m;
-        s->type = type;
-        s->family = family;
-        s->address = *in_addr;
-        s->ifindex = ifindex;
+        *s = (DnsServer) {
+                .n_ref = 1,
+                .manager = m,
+                .type = type,
+                .family = family,
+                .address = *in_addr,
+                .ifindex = ifindex,
+        };
 
         dns_server_reset_features(s);
 
@@ -101,7 +103,7 @@ int dns_server_new(
 static DnsServer* dns_server_free(DnsServer *s)  {
         assert(s);
 
-        dns_stream_unref(s->stream);
+        dns_server_unref_stream(s);
 
 #if ENABLE_DNS_OVER_TLS
         dnstls_server_free(s);
@@ -156,6 +158,9 @@ void dns_server_unlink(DnsServer *s) {
         if (s->manager->current_dns_server == s)
                 manager_set_dns_server(s->manager, NULL);
 
+        /* No need to keep a default stream around anymore */
+        dns_server_unref_stream(s);
+
         dns_server_unref(s);
 }
 
@@ -595,9 +600,7 @@ bool dns_server_limited_domains(DnsServer *server) {
         return domain_restricted;
 }
 
-static void dns_server_hash_func(const void *p, struct siphash *state) {
-        const DnsServer *s = p;
-
+static void dns_server_hash_func(const DnsServer *s, struct siphash *state) {
         assert(s);
 
         siphash24_compress(&s->family, sizeof(s->family), state);
@@ -605,8 +608,7 @@ static void dns_server_hash_func(const void *p, struct siphash *state) {
         siphash24_compress(&s->ifindex, sizeof(s->ifindex), state);
 }
 
-static int dns_server_compare_func(const void *a, const void *b) {
-        const DnsServer *x = a, *y = b;
+static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) {
         int r;
 
         r = CMP(x->family, y->family);
@@ -624,10 +626,7 @@ static int dns_server_compare_func(const void *a, const void *b) {
         return 0;
 }
 
-const struct hash_ops dns_server_hash_ops = {
-        .hash = dns_server_hash_func,
-        .compare = dns_server_compare_func
-};
+DEFINE_HASH_OPS(dns_server_hash_ops, DnsServer, dns_server_hash_func, dns_server_compare_func);
 
 void dns_server_unlink_all(DnsServer *first) {
         DnsServer *next;
@@ -830,6 +829,9 @@ void dns_server_reset_features(DnsServer *s) {
         s->warned_downgrade = false;
 
         dns_server_reset_counters(s);
+
+        /* Let's close the default stream, so that we reprobe with the new features */
+        dns_server_unref_stream(s);
 }
 
 void dns_server_reset_features_all(DnsServer *s) {
@@ -890,6 +892,20 @@ void dns_server_dump(DnsServer *s, FILE *f) {
                 yes_no(s->packet_rrsig_missing));
 }
 
+void dns_server_unref_stream(DnsServer *s) {
+        DnsStream *ref;
+
+        assert(s);
+
+        /* Detaches the default stream of this server. Some special care needs to be taken here, as that stream and
+         * this server reference each other. First, take the stream out of the server. It's destructor will check if it
+         * is registered with us, hence let's invalidate this separatly, so that it is already unregistered. */
+        ref = TAKE_PTR(s->stream);
+
+        /* And then, unref it */
+        dns_stream_unref(ref);
+}
+
 static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
         [DNS_SERVER_SYSTEM] = "system",
         [DNS_SERVER_FALLBACK] = "fallback",
index fda12510495ad8f1a2335273a27a964a8df0d546..6e73f32df45e581ba8784d08edb392069ceb29fd 100644 (file)
@@ -54,6 +54,8 @@ struct DnsServer {
         int ifindex; /* for IPv6 link-local DNS servers */
 
         char *server_string;
+
+        /* The long-lived stream towards this server. */
         DnsStream *stream;
 
 #if ENABLE_DNS_OVER_TLS
@@ -149,3 +151,5 @@ void dns_server_reset_features(DnsServer *s);
 void dns_server_reset_features_all(DnsServer *s);
 
 void dns_server_dump(DnsServer *s, FILE *f);
+
+void dns_server_unref_stream(DnsServer *s);
index 26d4663d746f38999575346e897899543cd6de7f..aee339a4c8d5679349101eccbed4d01e684360ec 100644 (file)
@@ -17,6 +17,9 @@ static void dns_stream_stop(DnsStream *s) {
         s->io_event_source = sd_event_source_unref(s->io_event_source);
         s->timeout_event_source = sd_event_source_unref(s->timeout_event_source);
         s->fd = safe_close(s->fd);
+
+        /* Disconnect us from the server object if we are now not usable anymore */
+        dns_stream_detach(s);
 }
 
 static int dns_stream_update_io(DnsStream *s) {
@@ -46,6 +49,8 @@ static int dns_stream_update_io(DnsStream *s) {
 }
 
 static int dns_stream_complete(DnsStream *s, int error) {
+        _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */
+
         assert(s);
 
 #if ENABLE_DNS_OVER_TLS
@@ -59,6 +64,8 @@ static int dns_stream_complete(DnsStream *s, int error) {
 #endif
                 dns_stream_stop(s);
 
+        dns_stream_detach(s);
+
         if (s->complete)
                 s->complete(s, error);
         else /* the default action if no completion function is set is to close the stream */
@@ -193,7 +200,7 @@ static int dns_stream_identify(DnsStream *s) {
 }
 
 ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags) {
-        ssize_t r;
+        ssize_t m;
 
         assert(s);
         assert(iov);
@@ -203,13 +210,13 @@ ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt,
                 ssize_t ss;
                 size_t i;
 
-                r = 0;
+                m = 0;
                 for (i = 0; i < iovcnt; i++) {
                         ss = dnstls_stream_write(s, iov[i].iov_base, iov[i].iov_len);
                         if (ss < 0)
                                 return ss;
 
-                        r += ss;
+                        m += ss;
                         if (ss != (ssize_t) iov[i].iov_len)
                                 continue;
                 }
@@ -223,28 +230,28 @@ ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt,
                         .msg_namelen = s->tfo_salen
                 };
 
-                r = sendmsg(s->fd, &hdr, MSG_FASTOPEN);
-                if (r < 0) {
+                m = sendmsg(s->fd, &hdr, MSG_FASTOPEN);
+                if (m < 0) {
                         if (errno == EOPNOTSUPP) {
                                 s->tfo_salen = 0;
-                                r = connect(s->fd, &s->tfo_address.sa, s->tfo_salen);
-                                if (r < 0)
+                                if (connect(s->fd, &s->tfo_address.sa, s->tfo_salen) < 0)
                                         return -errno;
 
-                                r = -EAGAIN;
-                        } else if (errno == EINPROGRESS)
-                                r = -EAGAIN;
-                        else
-                                r = -errno;
+                                return -EAGAIN;
+                        }
+                        if (errno == EINPROGRESS)
+                                return -EAGAIN;
+
+                        return -errno;
                 } else
                         s->tfo_salen = 0; /* connection is made */
         } else {
-                r = writev(s->fd, iov, iovcnt);
-                if (r < 0)
-                        r = -errno;
+                m = writev(s->fd, iov, iovcnt);
+                if (m < 0)
+                        return -errno;
         }
 
-        return r;
+        return m;
 }
 
 static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
@@ -258,7 +265,7 @@ static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
         {
                 ss = read(s->fd, buf, count);
                 if (ss < 0)
-                        ss = -errno;
+                        return -errno;
         }
 
         return ss;
@@ -273,7 +280,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
 }
 
 static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
-        DnsStream *s = userdata;
+        _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
         int r;
 
         assert(s);
@@ -281,18 +288,16 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
 #if ENABLE_DNS_OVER_TLS
         if (s->encrypted) {
                 r = dnstls_stream_on_io(s, revents);
-
                 if (r == DNSTLS_STREAM_CLOSED)
                         return 0;
-                else if (r == -EAGAIN)
+                if (r == -EAGAIN)
                         return dns_stream_update_io(s);
-                else if (r < 0) {
+                if (r < 0)
                         return dns_stream_complete(s, -r);
-                } else {
-                        r = dns_stream_update_io(s);
-                        if (r < 0)
-                                return r;
-                }
+
+                r = dns_stream_update_io(s);
+                if (r < 0)
+                        return r;
         }
 #endif
 
@@ -430,9 +435,6 @@ static DnsStream *dns_stream_free(DnsStream *s) {
 
         dns_stream_stop(s);
 
-        if (s->server && s->server->stream == s)
-                s->server->stream = NULL;
-
         if (s->manager) {
                 LIST_REMOVE(streams, s->manager->dns_streams, s);
                 s->manager->n_dns_streams--;
@@ -457,28 +459,37 @@ static DnsStream *dns_stream_free(DnsStream *s) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsStream, dns_stream, dns_stream_free);
 
-int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address) {
+int dns_stream_new(
+                Manager *m,
+                DnsStream **ret,
+                DnsProtocol protocol,
+                int fd,
+                const union sockaddr_union *tfo_address) {
+
         _cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
         int r;
 
         assert(m);
+        assert(ret);
         assert(fd >= 0);
 
         if (m->n_dns_streams > DNS_STREAMS_MAX)
                 return -EBUSY;
 
-        s = new0(DnsStream, 1);
+        s = new(DnsStream, 1);
         if (!s)
                 return -ENOMEM;
 
+        *s = (DnsStream) {
+                .n_ref = 1,
+                .fd = -1,
+                .protocol = protocol,
+        };
+
         r = ordered_set_ensure_allocated(&s->write_queue, &dns_packet_hash_ops);
         if (r < 0)
                 return r;
 
-        s->n_ref = 1;
-        s->fd = -1;
-        s->protocol = protocol;
-
         r = sd_event_add_io(m->event, &s->io_event_source, fd, EPOLLIN, on_stream_io, s);
         if (r < 0)
                 return r;
@@ -497,15 +508,16 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, co
         (void) sd_event_source_set_description(s->timeout_event_source, "dns-stream-timeout");
 
         LIST_PREPEND(streams, m->dns_streams, s);
+        m->n_dns_streams++;
         s->manager = m;
+
         s->fd = fd;
+
         if (tfo_address) {
                 s->tfo_address = *tfo_address;
                 s->tfo_salen = tfo_address->sa.sa_family == AF_INET6 ? sizeof(tfo_address->in6) : sizeof(tfo_address->in);
         }
 
-        m->n_dns_streams++;
-
         *ret = TAKE_PTR(s);
 
         return 0;
@@ -515,6 +527,7 @@ int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
         int r;
 
         assert(s);
+        assert(p);
 
         r = ordered_set_put(s->write_queue, p);
         if (r < 0)
@@ -524,3 +537,31 @@ int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
 
         return dns_stream_update_io(s);
 }
+
+DnsPacket *dns_stream_take_read_packet(DnsStream *s) {
+        assert(s);
+
+        if (!s->read_packet)
+                return NULL;
+
+        if (s->n_read < sizeof(s->read_size))
+                return NULL;
+
+        if (s->n_read < sizeof(s->read_size) + be16toh(s->read_size))
+                return NULL;
+
+        s->n_read = 0;
+        return TAKE_PTR(s->read_packet);
+}
+
+void dns_stream_detach(DnsStream *s) {
+        assert(s);
+
+        if (!s->server)
+                return;
+
+        if (s->server->stream != s)
+                return;
+
+        dns_server_unref_stream(s->server);
+}
index 46d2704afefdde6da94d0004628af26ad6faacbb..f18fc919e7399ee81ea922b8df412c85cadab72b 100644 (file)
@@ -53,13 +53,12 @@ struct DnsStream {
         size_t n_written, n_read;
         OrderedSet *write_queue;
 
-        int (*on_connection)(DnsStream *s);
         int (*on_packet)(DnsStream *s);
         int (*complete)(DnsStream *s, int error);
 
         LIST_HEAD(DnsTransaction, transactions); /* when used by the transaction logic */
         DnsServer *server;                       /* when used by the transaction logic */
-        DnsQuery *query;             /* when used by the DNS stub logic */
+        DnsQuery *query;                         /* when used by the DNS stub logic */
 
         /* used when DNS-over-TLS is enabled */
         bool encrypted:1;
@@ -87,3 +86,7 @@ static inline bool DNS_STREAM_QUEUED(DnsStream *s) {
 
         return !!s->write_packet;
 }
+
+DnsPacket *dns_stream_take_read_packet(DnsStream *s);
+
+void dns_stream_detach(DnsStream *s);
index c8c4d829e844840a993ee23f19d657aeb5121be7..a00716cd857072344295911ebd8b09f462857a87 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fd-util.h"
+#include "missing_network.h"
 #include "resolved-dns-stub.h"
 #include "socket-util.h"
 
@@ -436,13 +437,17 @@ static int manager_dns_stub_udp_fd(Manager *m) {
 }
 
 static int on_dns_stub_stream_packet(DnsStream *s) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+
         assert(s);
-        assert(s->read_packet);
 
-        if (dns_packet_validate_query(s->read_packet) > 0) {
-                log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
+        p = dns_stream_take_read_packet(s);
+        assert(p);
+
+        if (dns_packet_validate_query(p) > 0) {
+                log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(p));
 
-                dns_stub_process_query(s->manager, s, s->read_packet);
+                dns_stub_process_query(s->manager, s, p);
         } else
                 log_debug("Invalid DNS stub TCP packet, ignoring.");
 
index 9a8ce7ae2d8dfdbd97ca8216310f86d07bcbec76..f65116c3b45462f93109267c6386aa1422c97ca0 100644 (file)
@@ -3,6 +3,7 @@
 #include "alloc-util.h"
 #include "hostname-util.h"
 #include "local-addresses.h"
+#include "missing_network.h"
 #include "resolved-dns-synthesize.h"
 
 int dns_synthesize_ifindex(int ifindex) {
index ddab2850dfdf113b6ba1004a49ec2e0de56078f7..cc748ac95eac03118e0c5935e26727a8c1cb3e86 100644 (file)
@@ -503,59 +503,54 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) {
 }
 
 static int on_stream_complete(DnsStream *s, int error) {
-        _cleanup_(dns_stream_unrefp) DnsStream *p = NULL;
-        DnsTransaction *t, *n;
-        int r = 0;
-
-        /* Do not let new transactions use this stream */
-        if (s->server && s->server->stream == s)
-                p = TAKE_PTR(s->server->stream);
+        assert(s);
 
         if (ERRNO_IS_DISCONNECT(error) && s->protocol != DNS_PROTOCOL_LLMNR) {
-                usec_t usec;
-
                 log_debug_errno(error, "Connection failure for DNS TCP stream: %m");
 
                 if (s->transactions) {
+                        DnsTransaction *t;
+
                         t = s->transactions;
-                        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
                         dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level);
                 }
         }
 
-        LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions)
-                if (error != 0)
+        if (error != 0) {
+                DnsTransaction *t, *n;
+
+                LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions)
                         on_transaction_stream_error(t, error);
-                else if (DNS_PACKET_ID(s->read_packet) == t->id)
-                        /* As each transaction have a unique id the return code is only set once */
-                        r = dns_transaction_on_stream_packet(t, s->read_packet);
+        }
 
-        return r;
+        return 0;
 }
 
-static int dns_stream_on_packet(DnsStream *s) {
+static int on_stream_packet(DnsStream *s) {
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        int r = 0;
         DnsTransaction *t;
 
+        assert(s);
+
         /* Take ownership of packet to be able to receive new packets */
-        p = TAKE_PTR(s->read_packet);
-        s->n_read = 0;
+        p = dns_stream_take_read_packet(s);
+        assert(p);
 
         t = hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
+        if (t)
+                return dns_transaction_on_stream_packet(t, p);
 
         /* Ignore incorrect transaction id as transaction can have been canceled */
-        if (t)
-                r = dns_transaction_on_stream_packet(t, p);
-        else {
-                if (dns_packet_validate_reply(p) <= 0) {
-                        log_debug("Invalid TCP reply packet.");
-                        on_stream_complete(s, 0);
-                }
-                return 0;
+        if (dns_packet_validate_reply(p) <= 0) {
+                log_debug("Invalid TCP reply packet.");
+                on_stream_complete(s, 0);
         }
 
-        return r;
+        return 0;
+}
+
+static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
+        return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53;
 }
 
 static int dns_transaction_emit_tcp(DnsTransaction *t) {
@@ -585,7 +580,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                 if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted))
                         s = dns_stream_ref(t->server->stream);
                 else
-                        fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53, &sa);
+                        fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
 
                 break;
 
@@ -629,7 +624,9 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                 fd = -1;
 
 #if ENABLE_DNS_OVER_TLS
-                if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) {
+                if (t->scope->protocol == DNS_PROTOCOL_DNS &&
+                    DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) {
+
                         assert(t->server);
                         r = dnstls_stream_connect_tls(s, t->server);
                         if (r < 0)
@@ -638,13 +635,13 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
 #endif
 
                 if (t->server) {
-                        dns_stream_unref(t->server->stream);
+                        dns_server_unref_stream(t->server);
                         t->server->stream = dns_stream_ref(s);
                         s->server = dns_server_ref(t->server);
                 }
 
                 s->complete = on_stream_complete;
-                s->on_packet = dns_stream_on_packet;
+                s->on_packet = on_stream_packet;
 
                 /* The interface index is difficult to determine if we are
                  * connecting to the local host, hence fill this in right away
index c2db31df0fdfd8dde3bdbd6249fb02b875e9c34d..24bb37b35e848eaaf59195267ad887046f94b508 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "alloc-util.h"
 #include "bus-util.h"
+#include "missing_capability.h"
 #include "resolved-dnssd.h"
 #include "resolved-dnssd-bus.h"
 #include "resolved-link.h"
index ea96255dc1980b79845e963ee8fdc4bd731027b1..2c28ec227a5c601c053ccb7e3883e984255c9f4b 100644 (file)
@@ -228,10 +228,10 @@ int dnssd_update_rrs(DnssdService *s) {
         if (r < 0)
                 return r;
 
-        r = dns_name_concat(s->type, "local", &service_name);
+        r = dns_name_concat(s->type, "local", 0, &service_name);
         if (r < 0)
                 return r;
-        r = dns_name_concat(n, service_name, &full_name);
+        r = dns_name_concat(n, service_name, 0, &full_name);
         if (r < 0)
                 return r;
 
index bdd37a637f28bb5f31723e8e7ccfa9b00679bc95..f269e4d6487fd6dd0621c3aa41767bc52459404f 100644 (file)
@@ -7,6 +7,7 @@
 #include <openssl/bio.h>
 #include <openssl/err.h>
 
+#include "io-util.h"
 #include "resolved-dns-stream.h"
 #include "resolved-dnstls.h"
 
index c5c180943da086578cf4a3ca9073cbabdb616356..01cde4acf7b1e7ad0555507bc32b2f02eac08d62 100644 (file)
@@ -46,19 +46,20 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
 
         r = extract_first_word(&line, &address_str, NULL, EXTRACT_RELAX);
         if (r < 0)
-                return log_error_errno(r, "Couldn't extract address, in line /etc/hosts:%u.", nr);
-        if (r == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Premature end of line, in line /etc/hosts:%u.",
-                                       nr);
+                return log_error_errno(r, "/etc/hosts:%u: failed to extract address: %m", nr);
+        assert(r > 0); /* We already checked that the line is not empty, so it should contain *something* */
 
         r = in_addr_ifindex_from_string_auto(address_str, &address.family, &address.address, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Address '%s' is invalid, in line /etc/hosts:%u.", address_str, nr);
+        if (r < 0) {
+                log_warning_errno(r, "/etc/hosts:%u: address '%s' is invalid, ignoring: %m", nr, address_str);
+                return 0;
+        }
 
         r = in_addr_is_null(address.family, &address.address);
-        if (r < 0)
-                return r;
+        if (r < 0) {
+                log_warning_errno(r, "/etc/hosts:%u: address '%s' is invalid, ignoring: %m", nr, address_str);
+                return 0;
+        }
         if (r > 0)
                 /* This is an 0.0.0.0 or :: item, which we assume means that we shall map the specified hostname to
                  * nothing. */
@@ -92,16 +93,18 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
 
                 r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX);
                 if (r < 0)
-                        return log_error_errno(r, "Couldn't extract host name, in line /etc/hosts:%u.", nr);
+                        return log_error_errno(r, "/etc/hosts:%u: couldn't extract host name: %m", nr);
                 if (r == 0)
                         break;
 
-                r = dns_name_is_valid(name);
-                if (r <= 0)
-                        return log_error_errno(r, "Hostname %s is not valid, ignoring, in line /etc/hosts:%u.", name, nr);
-
                 found = true;
 
+                r = dns_name_is_valid_ldh(name);
+                if (r <= 0) {
+                        log_warning_errno(r, "/etc/hosts:%u: hostname \"%s\" is not valid, ignoring.", nr, name);
+                        continue;
+                }
+
                 if (is_localhost(name))
                         /* Suppress the "localhost" line that is often seen */
                         continue;
@@ -152,9 +155,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
         }
 
         if (!found)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Line is missing any host names, in line /etc/hosts:%u.",
-                                       nr);
+                log_warning("/etc/hosts:%u: line is missing any host names", nr);
 
         return 0;
 }
@@ -176,11 +177,13 @@ int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
 
                 nr++;
 
+                l = strchr(line, '#');
+                if (l)
+                        *l = '\0';
+
                 l = strstrip(line);
                 if (isempty(l))
                         continue;
-                if (l[0] == '#')
-                        continue;
 
                 r = parse_line(&t, nr, l);
                 if (r < 0)
index 0ae3b400181c862d4303ac7503c12f988679f9a9..2cfb848a8b404458673c6c547c832e29d3fd459e 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-network.h"
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "missing.h"
@@ -16,6 +17,7 @@
 #include "resolved-mdns.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 
 int link_new(Manager *m, Link **ret, int ifindex) {
         _cleanup_(link_freep) Link *l = NULL;
index 65f5ceecd01ba860ce7da650bb9ddb1176d8d6d7..dfa55c577c402a1575379ab0f74b041346830c45 100644 (file)
@@ -260,18 +260,21 @@ int manager_llmnr_ipv6_udp_fd(Manager *m) {
 }
 
 static int on_llmnr_stream_packet(DnsStream *s) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
         DnsScope *scope;
 
         assert(s);
-        assert(s->read_packet);
 
-        scope = manager_find_scope(s->manager, s->read_packet);
+        p = dns_stream_take_read_packet(s);
+        assert(p);
+
+        scope = manager_find_scope(s->manager, p);
         if (!scope)
                 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
-        else if (dns_packet_validate_query(s->read_packet) > 0) {
-                log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
+        else if (dns_packet_validate_query(p) > 0) {
+                log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(p));
 
-                dns_scope_process_query(scope, s, s->read_packet);
+                dns_scope_process_query(scope, s, p);
         } else
                 log_debug("Invalid LLMNR TCP packet, ignoring.");
 
index 0fdc84d57af14e8d686303e69f41caa1a488d04a..1f8c47ccbebe0a4bb03055292dbcc863a56419d3 100644 (file)
 #include "dirent-util.h"
 #include "dns-domain.h"
 #include "fd-util.h"
-#include "fileio-label.h"
+#include "fileio.h"
 #include "hostname-util.h"
 #include "io-util.h"
-#include "io-util.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "ordered-set.h"
@@ -334,7 +334,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
                 return log_debug_errno(r, "Can't determine system hostname: %m");
 
         p = h;
-        r = dns_label_unescape(&p, label, sizeof label);
+        r = dns_label_unescape(&p, label, sizeof label, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to unescape host name: %m");
         if (r == 0)
@@ -372,7 +372,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "System hostname is 'localhost', ignoring.");
 
-        r = dns_name_concat(n, "local", mdns_hostname);
+        r = dns_name_concat(n, "local", 0, mdns_hostname);
         if (r < 0)
                 return log_error_errno(r, "Failed to determine mDNS hostname: %m");
 
@@ -404,7 +404,7 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
         assert(mdns_hostname);
 
         p = fallback_hostname();
-        r = dns_label_unescape(&p, label, sizeof(label));
+        r = dns_label_unescape(&p, label, sizeof label, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to unescape fallback host name: %m");
 
@@ -414,7 +414,7 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
         if (r < 0)
                 return log_error_errno(r, "Failed to escape fallback hostname: %m");
 
-        r = dns_name_concat(n, "local", &m);
+        r = dns_name_concat(n, "local", 0, &m);
         if (r < 0)
                 return log_error_errno(r, "Failed to concatenate mDNS hostname: %m");
 
@@ -1148,7 +1148,7 @@ int manager_next_hostname(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = dns_name_concat(h, "local", &k);
+        r = dns_name_concat(h, "local", 0, &k);
         if (r < 0)
                 return r;
 
index f8b5301c1ed8424469672cb29f9658df3fb15bf6..ad47d13d238891f452bed617975bb3cd997e5f57 100644 (file)
@@ -6,7 +6,6 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "fd-util.h"
-#include "fileio-label.h"
 #include "fileio.h"
 #include "ordered-set.h"
 #include "resolved-conf.h"
@@ -14,6 +13,7 @@
 #include "resolved-resolv-conf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util-label.h"
 
 /* A resolv.conf file containing the DNS server and domain data we learnt from uplink, i.e. the full uplink data */
 #define PRIVATE_UPLINK_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
index 755477096d59067fd0e4c89dc1c23cea12dc6c43..f4efddf8e5b66ae935d4de18eb84197d724c0f25 100644 (file)
@@ -4,6 +4,8 @@
 #include "sd-event.h"
 
 #include "capability-util.h"
+#include "daemon-util.h"
+#include "main-func.h"
 #include "mkdir.h"
 #include "resolved-conf.h"
 #include "resolved-manager.h"
@@ -12,7 +14,8 @@
 #include "signal-util.h"
 #include "user-util.h"
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+        _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
         const char *user = "systemd-resolve";
         uid_t uid;
@@ -21,32 +24,23 @@ int main(int argc, char *argv[]) {
 
         log_setup_service();
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                r = -EINVAL;
-                goto finish;
-        }
+        if (argc != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
 
         umask(0022);
 
         r = mac_selinux_init();
-        if (r < 0) {
-                log_error_errno(r, "SELinux setup failed: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "SELinux setup failed: %m");
 
         r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
-        if (r < 0) {
-                log_error_errno(r, "Cannot resolve user name %s: %m", user);
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Cannot resolve user name %s: %m", user);
 
         /* Always create the directory where resolv.conf will live */
         r = mkdir_safe_label("/run/systemd/resolve", 0755, uid, gid, MKDIR_WARN_MODE);
-        if (r < 0) {
-                log_error_errno(r, "Could not create runtime directory: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not create runtime directory: %m");
 
         /* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
          * privileges are already dropped. */
@@ -58,22 +52,18 @@ int main(int argc, char *argv[]) {
                                     (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;
+                        return log_error_errno(r, "Failed to drop privileges: %m");
         }
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
 
         r = manager_new(&m);
-        if (r < 0) {
-                log_error_errno(r, "Could not create manager: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not create manager: %m");
 
         r = manager_start(m);
-        if (r < 0) {
-                log_error_errno(r, "Failed to start manager: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to start manager: %m");
 
         /* Write finish default resolv.conf to avoid a dangling symlink */
         (void) manager_write_resolv_conf(m);
@@ -82,27 +72,18 @@ int main(int argc, char *argv[]) {
 
         /* Let's drop the remaining caps now */
         r = capability_bounding_set_drop(0, true);
-        if (r < 0) {
-                log_error_errno(r, "Failed to drop remaining caps: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to drop remaining caps: %m");
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
+        notify_stop = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
 
         r = sd_event_loop(m->event);
-        if (r < 0) {
-                log_error_errno(r, "Event loop failed: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Event loop failed: %m");
 
-        sd_event_get_exit_code(m->event, &r);
+        (void) sd_event_get_exit_code(m->event, &r);
 
-finish:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return r;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index 0dac05e7bed6cb327899f4be7b611ba8f7b17274..f6df9135ee936410bf82c0cd139fce5c802b2053 100644 (file)
@@ -103,7 +103,7 @@ int main(int argc, char **argv) {
                 N = argc - 1;
                 fnames = argv + 1;
         } else {
-                pkts_glob = path_join(NULL, get_testdata_dir(), "test-resolve/*.pkts");
+                pkts_glob = path_join(get_testdata_dir(), "test-resolve/*.pkts");
                 assert_se(glob(pkts_glob, GLOB_NOSORT, NULL, &g) == 0);
                 N = g.gl_pathc;
                 fnames = g.gl_pathv;
index 568d8e0790459f9bdd5a5cbcef7b749bc2ff629a..840c4fa1db6e2c2149541e42ce24c82e2e4c1f5a 100644 (file)
@@ -497,7 +497,7 @@ static void test_dnssec_nsec3_hash(void) {
 
 #endif
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
 
         test_dnssec_canonicalize();
 
index 1b22e3820233354bc616ab58d7eeb74b16239ac5..dbff889e3ead91edc16e82fc547090cce87925f2 100644 (file)
@@ -1,17 +1,25 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
 #include "log.h"
 #include "resolved-etc-hosts.h"
+#include "strv.h"
+#include "tmpfile-util.h"
 
 static void test_parse_etc_hosts_system(void) {
         _cleanup_fclose_ FILE *f = NULL;
 
+        log_info("/* %s */", __func__);
+
         f = fopen("/etc/hosts", "re");
         if (!f) {
-                assert_se(errno == -ENOENT);
+                assert_se(errno == ENOENT);
                 return;
         }
 
@@ -19,59 +27,98 @@ static void test_parse_etc_hosts_system(void) {
         assert_se(etc_hosts_parse(&hosts, f) == 0);
 }
 
-static void test_parse_etc_hosts(const char *fname) {
+#define address_equal_4(_addr, _address)                                \
+        ((_addr)->family == AF_INET &&                                  \
+         !memcmp(&(_addr)->address.in, &(struct in_addr) { .s_addr = (_address) }, 4))
+
+#define address_equal_6(_addr, ...)                                     \
+        ((_addr)->family == AF_INET6 &&                                 \
+         !memcmp(&(_addr)->address.in6, &(struct in6_addr) { .s6_addr = __VA_ARGS__}, 16) )
+
+static void test_parse_etc_hosts(void) {
         _cleanup_(unlink_tempfilep) char
                 t[] = "/tmp/test-resolved-etc-hosts.XXXXXX";
 
+        log_info("/* %s */", __func__);
+
         int fd;
         _cleanup_fclose_ FILE *f;
-
-        if (fname) {
-                f = fopen(fname, "re");
-                assert_se(f);
-        } else {
-                fd = mkostemp_safe(t);
-                assert_se(fd >= 0);
-
-                f = fdopen(fd, "r+");
-                assert_se(f);
-                fputs("1.2.3.4 some.where\n", f);
-                fputs("1.2.3.5 some.where\n", f);
-                fputs("::0 some.where some.other\n", f);
-                fputs("0.0.0.0 black.listed\n", f);
-                fputs("::5 some.where some.other foobar.foo.foo\n", f);
-                fputs("        \n", f);
-                fflush(f);
-                rewind(f);
-        }
+        const char *s;
+
+        fd = mkostemp_safe(t);
+        assert_se(fd >= 0);
+
+        f = fdopen(fd, "r+");
+        assert_se(f);
+        fputs("1.2.3.4 some.where\n"
+              "1.2.3.5 some.where\n"
+              "1.2.3.6 dash dash-dash.where-dash\n"
+              "1.2.3.7 bad-dash- -bad-dash -bad-dash.bad-\n"
+              "1.2.3.8\n"
+              "1.2.3.9 before.comment # within.comment\n"
+              "1.2.3.10 before.comment#within.comment2\n"
+              "1.2.3.11 before.comment# within.comment3\n"
+              "1.2.3.12 before.comment#\n"
+              "1.2.3 short.address\n"
+              "1.2.3.4.5 long.address\n"
+              "1::2::3 multi.colon\n"
+
+              "::0 some.where some.other\n"
+              "0.0.0.0 black.listed\n"
+              "::5\t\t\t \tsome.where\tsome.other foobar.foo.foo\t\t\t\n"
+              "        \n", f);
+        assert_se(fflush_and_check(f) >= 0);
+        rewind(f);
 
         _cleanup_(etc_hosts_free) EtcHosts hosts = {};
         assert_se(etc_hosts_parse(&hosts, f) == 0);
 
-        if (fname)
-                return;
-
         EtcHostsItemByName *bn;
         assert_se(bn = hashmap_get(hosts.by_name, "some.where"));
         assert_se(bn->n_addresses == 3);
         assert_se(bn->n_allocated >= 3);
+        assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.4")));
+        assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.5")));
+        assert_se(address_equal_6(bn->addresses[2], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
 
-        assert_se(bn->addresses[0]->family == AF_INET);
-        assert_se(memcmp(&bn->addresses[0]->address.in,
-                         &(struct in_addr) { .s_addr = htobe32(0x01020304) }, 4) == 0);
-        assert_se(bn->addresses[1]->family == AF_INET);
-        assert_se(memcmp(&bn->addresses[1]->address.in,
-                         &(struct in_addr) { .s_addr = htobe32(0x01020305) }, 4) == 0);
-        assert_se(bn->addresses[2]->family == AF_INET6);
-        assert_se(memcmp(&bn->addresses[2]->address.in6,
-                         &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+        assert_se(bn = hashmap_get(hosts.by_name, "dash"));
+        assert_se(bn->n_addresses == 1);
+        assert_se(bn->n_allocated >= 1);
+        assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
+
+        assert_se(bn = hashmap_get(hosts.by_name, "dash-dash.where-dash"));
+        assert_se(bn->n_addresses == 1);
+        assert_se(bn->n_allocated >= 1);
+        assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
+
+        /* See https://tools.ietf.org/html/rfc1035#section-2.3.1 */
+        FOREACH_STRING(s, "bad-dash-", "-bad-dash", "-bad-dash.bad-")
+                assert_se(!hashmap_get(hosts.by_name, s));
+
+        assert_se(bn = hashmap_get(hosts.by_name, "before.comment"));
+        assert_se(bn->n_addresses == 4);
+        assert_se(bn->n_allocated >= 4);
+        assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.9")));
+        assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.10")));
+        assert_se(address_equal_4(bn->addresses[2], inet_addr("1.2.3.11")));
+        assert_se(address_equal_4(bn->addresses[3], inet_addr("1.2.3.12")));
+
+        assert(!hashmap_get(hosts.by_name, "within.comment"));
+        assert(!hashmap_get(hosts.by_name, "within.comment2"));
+        assert(!hashmap_get(hosts.by_name, "within.comment3"));
+        assert(!hashmap_get(hosts.by_name, "#"));
+
+        assert(!hashmap_get(hosts.by_name, "short.address"));
+        assert(!hashmap_get(hosts.by_name, "long.address"));
+        assert(!hashmap_get(hosts.by_name, "multi.colon"));
+        assert_se(!set_contains(hosts.no_address, "short.address"));
+        assert_se(!set_contains(hosts.no_address, "long.address"));
+        assert_se(!set_contains(hosts.no_address, "multi.colon"));
 
         assert_se(bn = hashmap_get(hosts.by_name, "some.other"));
         assert_se(bn->n_addresses == 1);
         assert_se(bn->n_allocated >= 1);
-        assert_se(bn->addresses[0]->family == AF_INET6);
-        assert_se(memcmp(&bn->addresses[0]->address.in6,
-                         &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+        assert_se(address_equal_6(bn->addresses[0], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
 
         assert_se( set_contains(hosts.no_address, "some.where"));
         assert_se( set_contains(hosts.no_address, "some.other"));
@@ -79,14 +126,26 @@ static void test_parse_etc_hosts(const char *fname) {
         assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
 }
 
+static void test_parse_file(const char *fname) {
+        _cleanup_(etc_hosts_free) EtcHosts hosts = {};
+        _cleanup_fclose_ FILE *f;
+
+        log_info("/* %s(\"%s\") */", __func__, fname);
+
+        assert_se(f = fopen(fname, "re"));
+        assert_se(etc_hosts_parse(&hosts, f) == 0);
+}
+
 int main(int argc, char **argv) {
         log_set_max_level(LOG_DEBUG);
         log_parse_environment();
         log_open();
 
-        if (argc == 1)
+        if (argc == 1) {
                 test_parse_etc_hosts_system();
-        test_parse_etc_hosts(argv[1]);
+                test_parse_etc_hosts();
+        } else
+                test_parse_file(argv[1]);
 
         return 0;
 }
index 37441a8f5b0883972a08a2d32f55e34ac1d7d129..246e27a13579457b6ed82ac12b521e5961f6b84e 100644 (file)
@@ -41,6 +41,7 @@
 #include "strv.h"
 #include "terminal-util.h"
 #include "time-util.h"
+#include "tmpfile-util.h"
 #include "umask-util.h"
 #include "utf8.h"
 #include "util.h"
index e4eb600ed6c7f39f27d74062a0fe57c9e19128c4..eb07a88ba98ee67091d9777594311d08a343078b 100644 (file)
@@ -2,11 +2,9 @@
 #pragma once
 
 #if HAVE_BLKID
-#include <blkid.h>
-#endif
+#  include <blkid.h>
 
-#include "util.h"
+#  include "macro.h"
 
-#if HAVE_BLKID
 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
 #endif
index db4fd411e2841837db31db6c88b35768c1252d72..7e276f1edf58001755cf93cb09d9c969e50b947a 100644 (file)
@@ -405,7 +405,7 @@ static int verify_esp(
                 sd_id128_t *ret_uuid) {
 #if HAVE_BLKID
         _cleanup_(blkid_free_probep) blkid_probe b = NULL;
-        char t[DEV_NUM_PATH_MAX];
+        _cleanup_free_ char *node = NULL;
         const char *v;
 #endif
         uint64_t pstart = 0, psize = 0;
@@ -469,9 +469,11 @@ static int verify_esp(
                 goto finish;
 
 #if HAVE_BLKID
-        xsprintf_dev_num_path(t, "block", st.st_dev);
+        r = device_path_make_major_minor(S_IFBLK, st.st_dev, &node);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format major/minor device path: %m");
         errno = 0;
-        b = blkid_new_probe_from_filename(t);
+        b = blkid_new_probe_from_filename(node);
         if (!b)
                 return log_error_errno(errno ?: ENOMEM, "Failed to open file system \"%s\": %m", p);
 
index d11b8c26c7457208858f256002ddb54b975c36fb..e324a2ffc7fce9f4d5b0f7b9343e3a33e424e276 100644 (file)
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
+#include "ip-protocol-list.h"
 #include "list.h"
 #include "locale-util.h"
-#include "mount-util.h"
+#include "missing_fs.h"
+#include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -25,7 +27,6 @@
 #include "rlimit-util.h"
 #include "securebits-util.h"
 #include "signal-util.h"
-#include "socket-protocol-list.h"
 #include "string-util.h"
 #include "syslog-util.h"
 #include "terminal-util.h"
@@ -103,7 +104,7 @@ DEFINE_BUS_APPEND_PARSE("i", parse_errno);
 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
 DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
-DEFINE_BUS_APPEND_PARSE("i", socket_protocol_from_name);
+DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
@@ -1466,7 +1467,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
 
         if (streq(field, "SocketProtocol"))
 
-                return bus_append_socket_protocol_from_name(m, field, eq);
+                return bus_append_parse_ip_protocol(m, field, eq);
 
         if (STR_IN_SET(field,
                        "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
index 760be38c85d052095f6b950dca5a1b9337cf5671..976643e4ce0a4df3ec513c6d0707192059dcd7c7 100644 (file)
@@ -28,7 +28,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
@@ -1237,44 +1237,6 @@ int bus_message_map_all_properties(
         return sd_bus_message_exit_container(m);
 }
 
-int bus_message_map_properties_changed(
-                sd_bus_message *m,
-                const struct bus_properties_map *map,
-                unsigned flags,
-                sd_bus_error *error,
-                void *userdata) {
-
-        const char *member;
-        int r, invalidated, i;
-
-        assert(m);
-        assert(map);
-
-        r = bus_message_map_all_properties(m, map, flags, error, userdata);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
-        if (r < 0)
-                return r;
-
-        invalidated = 0;
-        while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
-                for (i = 0; map[i].member; i++)
-                        if (streq(map[i].member, member)) {
-                                ++invalidated;
-                                break;
-                        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return invalidated;
-}
-
 int bus_map_all_properties(
                 sd_bus *bus,
                 const char *destination,
index 3d3cdecb43e1c5932a8d9182a6ac6b2b9b53f633..71c248fe3c7106ded9f3fd587b80e48deedf9854 100644 (file)
@@ -38,7 +38,6 @@ enum {
 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
 
 int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, unsigned flags, sd_bus_error *error, void *userdata);
-int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, unsigned flags, sd_bus_error *error, void *userdata);
 int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map,
                            unsigned flags, sd_bus_error *error, sd_bus_message **reply, void *userdata);
 
index 36a611c3c10345d57b11228cd6878518a9fbae22..988a354ae36d7408dbffbe2695938e8d2e5df629 100644 (file)
@@ -12,8 +12,8 @@
 #include "bus-util.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
+#include "env-file.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "locale-util.h"
 #include "macro.h"
@@ -277,26 +277,6 @@ int show_cgroup_and_extra(
         return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
 }
 
-int show_cgroup_and_extra_by_spec(
-                const char *spec,
-                const char *prefix,
-                unsigned n_columns,
-                const pid_t extra_pids[],
-                unsigned n_extra_pids,
-                OutputFlags flags) {
-
-        _cleanup_free_ char *controller = NULL, *path = NULL;
-        int r;
-
-        assert(spec);
-
-        r = cg_split_spec(spec, &controller, &path);
-        if (r < 0)
-                return r;
-
-        return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
-}
-
 int show_cgroup_get_unit_path_and_warn(
                 sd_bus *bus,
                 const char *unit,
index 4e510fb73c8047ae0b7c4bbb78c89ae38d258724..3593e9dcf43adcc9a1a0f371e2bf604b90a73785 100644 (file)
@@ -12,7 +12,6 @@
 int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags);
 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags);
 
-int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
 int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
 
 int show_cgroup_get_unit_path_and_warn(
index ecc32beadfb6dd623160c463de9b79d1f04dca4b..fb77966264e41a85f475f0d0a5d941a7918111c4 100644 (file)
@@ -30,7 +30,8 @@
 #include "ima-util.h"
 #include "list.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
+#include "env-file.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index 8110b2cb16884e66bc8f2e0250463365d3780148..8fe177990a6b7ae975f4d9cff0b1d94ad1b19546 100644 (file)
 #include "fs-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
 #include "string-util.h"
@@ -28,7 +30,6 @@
 #include "syslog-util.h"
 #include "time-util.h"
 #include "utf8.h"
-#include "rlimit-util.h"
 
 int config_item_table_lookup(
                 const void *table,
diff --git a/src/shared/daemon-util.h b/src/shared/daemon-util.h
new file mode 100644 (file)
index 0000000..5e9eca1
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "sd-daemon.h"
+
+#define NOTIFY_READY "READY=1\n" "STATUS=Processing requests..."
+#define NOTIFY_STOPPING "STOPPING=1\n" "STATUS=Shutting down..."
+
+static inline const char *notify_start(const char *start, const char *stop) {
+        if (start)
+                (void) sd_notify(false, start);
+
+        return stop;
+}
+
+/* This is intended to be used with _cleanup_ attribute. */
+static inline void notify_on_cleanup(const char **p) {
+        if (p)
+                (void) sd_notify(false, *p);
+}
index d117fbfda06f7117240c30624b4eb98cbb095fd7..b545c2a1c0e16d511b0075db27ce573c5f86f038 100644 (file)
@@ -9,6 +9,7 @@
 #include "label.h"
 #include "log.h"
 #include "path-util.h"
+#include "umask-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -54,3 +55,61 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
 
         return 0;
 }
+
+int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) {
+        static const struct {
+                const char *name;
+                mode_t mode;
+        } table[] = {
+                { "/run/systemd",                   S_IFDIR  | 0755 },
+                { "/run/systemd/inaccessible",      S_IFDIR  | 0000 },
+                { "/run/systemd/inaccessible/reg",  S_IFREG  | 0000 },
+                { "/run/systemd/inaccessible/dir",  S_IFDIR  | 0000 },
+                { "/run/systemd/inaccessible/fifo", S_IFIFO  | 0000 },
+                { "/run/systemd/inaccessible/sock", S_IFSOCK | 0000 },
+
+                /* The following two are likely to fail if we lack the privs for it (for example in an userns
+                 * environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0
+                 * device nodes to be created). But that's entirely fine. Consumers of these files should carry
+                 * fallback to use a different node then, for example /run/systemd/inaccessible/sock, which is close
+                 * enough in behaviour and semantics for most uses. */
+                { "/run/systemd/inaccessible/chr",  S_IFCHR  | 0000 },
+                { "/run/systemd/inaccessible/blk",  S_IFBLK  | 0000 },
+        };
+
+        _cleanup_umask_ mode_t u;
+        size_t i;
+        int r;
+
+        u = umask(0000);
+
+        /* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting
+         * ("masking") file nodes that shall become inaccessible and empty for specific containers or services. We try
+         * to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the
+         * underlying file, i.e. in the best case we offer the same node type as the underlying node. */
+
+        for (i = 0; i < ELEMENTSOF(table); i++) {
+                _cleanup_free_ char *path = NULL;
+
+                path = prefix_root(root, table[i].name);
+                if (!path)
+                        return log_oom();
+
+                if (S_ISDIR(table[i].mode))
+                        r = mkdir(path, table[i].mode & 07777);
+                else
+                        r = mknod(path, table[i].mode, makedev(0, 0));
+                if (r < 0) {
+                        if (errno != EEXIST)
+                                log_debug_errno(errno, "Failed to create '%s', ignoring: %m", path);
+                        continue;
+                }
+
+                if (uid != UID_INVALID || gid != GID_INVALID) {
+                        if (lchown(path, uid, gid) < 0)
+                                log_debug_errno(errno, "Failed to chown '%s': %m", path);
+                }
+        }
+
+        return 0;
+}
index f105f2f20f2995a03ccf7d65d6a8f26a31cd05db..72b90ec4de8acec7a573c75103555abb6507c844 100644 (file)
@@ -4,3 +4,5 @@
 #include <sys/types.h>
 
 int dev_setup(const char *prefix, uid_t uid, gid_t gid);
+
+int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid);
index 18620a3b195ea472b0cf1a4aa8ff466bd1594269..4e572ac861c5a18c24b633f593ee46888b9b16b9 100644 (file)
@@ -17,6 +17,7 @@
 #include "device-nodes.h"
 #include "device-util.h"
 #include "dissect-image.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
@@ -27,6 +28,7 @@
 #include "linux-3.13/dm-ioctl.h"
 #include "missing.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "os-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -37,6 +39,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "xattr-util.h"
 
@@ -219,8 +222,9 @@ int dissect_image(
                                         return -ENOMEM;
                         }
 
-                        if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
-                                return -ENOMEM;
+                        r = device_path_make_major_minor(st.st_mode, st.st_rdev, &n);
+                        if (r < 0)
+                                return r;
 
                         m->partitions[PARTITION_ROOT] = (DissectedPartition) {
                                 .found = true,
index f24edf579187754fe783db88cb968c15c10098dc..4b31cb36ede3790fc1cd760c1ad8ac9af37d561a 100644 (file)
@@ -17,6 +17,7 @@
 #include "dns-domain.h"
 #include "hashmap.h"
 #include "hexdecoct.h"
+#include "hostname-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
 #include "parse-util.h"
@@ -24,9 +25,9 @@
 #include "strv.h"
 #include "utf8.h"
 
-int dns_label_unescape(const char **name, char *dest, size_t sz) {
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags) {
         const char *n;
-        char *d;
+        char *d, last_char = 0;
         int r = 0;
 
         assert(name);
@@ -36,13 +37,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
         d = dest;
 
         for (;;) {
-                if (*n == '.') {
-                        n++;
-                        break;
-                }
+                if (*n == 0 || *n == '.') {
+                        if (FLAGS_SET(flags, DNS_LABEL_LDH) && last_char == '-')
+                                /* Trailing dash */
+                                return -EINVAL;
 
-                if (*n == 0)
+                        if (*n == '.')
+                                n++;
                         break;
+                }
 
                 if (r >= DNS_LABEL_MAX)
                         return -EINVAL;
@@ -52,6 +55,8 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
 
                 if (*n == '\\') {
                         /* Escaped character */
+                        if (FLAGS_SET(flags, DNS_LABEL_NO_ESCAPES))
+                                return -EINVAL;
 
                         n++;
 
@@ -62,6 +67,10 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
                         else if (IN_SET(*n, '\\', '.')) {
                                 /* Escaped backslash or dot */
 
+                                if (FLAGS_SET(flags, DNS_LABEL_LDH))
+                                        return -EINVAL;
+
+                                last_char = *n;
                                 if (d)
                                         *(d++) = *n;
                                 sz--;
@@ -90,6 +99,11 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
                                 if (k > 255)
                                         return -EINVAL;
 
+                                if (FLAGS_SET(flags, DNS_LABEL_LDH) &&
+                                    !valid_ldh_char((char) k))
+                                        return -EINVAL;
+
+                                last_char = (char) k;
                                 if (d)
                                         *(d++) = (char) k;
                                 sz--;
@@ -103,6 +117,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
 
                         /* Normal character */
 
+                        if (FLAGS_SET(flags, DNS_LABEL_LDH)) {
+                                if (!valid_ldh_char(*n))
+                                        return -EINVAL;
+                                if (r == 0 && *n == '-')
+                                        /* Leading dash */
+                                        return -EINVAL;
+                        }
+
+                        last_char = *n;
                         if (d)
                                 *(d++) = *n;
                         sz--;
@@ -184,7 +207,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
                 terminal--;
         }
 
-        r = dns_label_unescape(&name, dest, sz);
+        r = dns_label_unescape(&name, dest, sz, 0);
         if (r < 0)
                 return r;
 
@@ -378,7 +401,7 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
 }
 #endif
 
-int dns_name_concat(const char *a, const char *b, char **_ret) {
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
         _cleanup_free_ char *ret = NULL;
         size_t n = 0, allocated = 0;
         const char *p;
@@ -395,7 +418,7 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
         for (;;) {
                 char label[DNS_LABEL_MAX];
 
-                r = dns_label_unescape(&p, label, sizeof(label));
+                r = dns_label_unescape(&p, label, sizeof label, flags);
                 if (r < 0)
                         return r;
                 if (r == 0) {
@@ -460,8 +483,7 @@ finish:
         return 0;
 }
 
-void dns_name_hash_func(const void *s, struct siphash *state) {
-        const char *p = s;
+void dns_name_hash_func(const char *p, struct siphash *state) {
         int r;
 
         assert(p);
@@ -469,7 +491,7 @@ void dns_name_hash_func(const void *s, struct siphash *state) {
         for (;;) {
                 char label[DNS_LABEL_MAX+1];
 
-                r = dns_label_unescape(&p, label, sizeof(label));
+                r = dns_label_unescape(&p, label, sizeof label, 0);
                 if (r < 0)
                         break;
                 if (r == 0)
@@ -484,15 +506,15 @@ void dns_name_hash_func(const void *s, struct siphash *state) {
         string_hash_func("", state);
 }
 
-int dns_name_compare_func(const void *a, const void *b) {
+int dns_name_compare_func(const char *a, const char *b) {
         const char *x, *y;
         int r, q;
 
         assert(a);
         assert(b);
 
-        x = (const char *) a + strlen(a);
-        y = (const char *) b + strlen(b);
+        x = a + strlen(a);
+        y = b + strlen(b);
 
         for (;;) {
                 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
@@ -511,10 +533,7 @@ int dns_name_compare_func(const void *a, const void *b) {
         }
 }
 
-const struct hash_ops dns_name_hash_ops = {
-        .hash = dns_name_hash_func,
-        .compare = dns_name_compare_func
-};
+DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func);
 
 int dns_name_equal(const char *x, const char *y) {
         int r, q;
@@ -525,11 +544,11 @@ int dns_name_equal(const char *x, const char *y) {
         for (;;) {
                 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
 
-                r = dns_label_unescape(&x, la, sizeof(la));
+                r = dns_label_unescape(&x, la, sizeof la, 0);
                 if (r < 0)
                         return r;
 
-                q = dns_label_unescape(&y, lb, sizeof(lb));
+                q = dns_label_unescape(&y, lb, sizeof lb, 0);
                 if (q < 0)
                         return q;
 
@@ -556,14 +575,14 @@ int dns_name_endswith(const char *name, const char *suffix) {
         for (;;) {
                 char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
 
-                r = dns_label_unescape(&n, ln, sizeof(ln));
+                r = dns_label_unescape(&n, ln, sizeof ln, 0);
                 if (r < 0)
                         return r;
 
                 if (!saved_n)
                         saved_n = n;
 
-                q = dns_label_unescape(&s, ls, sizeof(ls));
+                q = dns_label_unescape(&s, ls, sizeof ls, 0);
                 if (q < 0)
                         return q;
 
@@ -594,13 +613,13 @@ int dns_name_startswith(const char *name, const char *prefix) {
         for (;;) {
                 char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
 
-                r = dns_label_unescape(&p, lp, sizeof(lp));
+                r = dns_label_unescape(&p, lp, sizeof lp, 0);
                 if (r < 0)
                         return r;
                 if (r == 0)
                         return true;
 
-                q = dns_label_unescape(&n, ln, sizeof(ln));
+                q = dns_label_unescape(&n, ln, sizeof ln, 0);
                 if (q < 0)
                         return q;
 
@@ -629,14 +648,14 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
                 if (!saved_before)
                         saved_before = n;
 
-                r = dns_label_unescape(&n, ln, sizeof(ln));
+                r = dns_label_unescape(&n, ln, sizeof ln, 0);
                 if (r < 0)
                         return r;
 
                 if (!saved_after)
                         saved_after = n;
 
-                q = dns_label_unescape(&s, ls, sizeof(ls));
+                q = dns_label_unescape(&s, ls, sizeof ls, 0);
                 if (q < 0)
                         return q;
 
@@ -659,7 +678,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
         /* Found it! Now generate the new name */
         prefix = strndupa(name, saved_before - name);
 
-        r = dns_name_concat(prefix, new_suffix, ret);
+        r = dns_name_concat(prefix, new_suffix, 0, ret);
         if (r < 0)
                 return r;
 
@@ -737,7 +756,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
                 for (i = 0; i < ELEMENTSOF(a); i++) {
                         char label[DNS_LABEL_MAX+1];
 
-                        r = dns_label_unescape(&p, label, sizeof(label));
+                        r = dns_label_unescape(&p, label, sizeof label, 0);
                         if (r < 0)
                                 return r;
                         if (r == 0)
@@ -774,7 +793,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
                         char label[DNS_LABEL_MAX+1];
                         int x, y;
 
-                        r = dns_label_unescape(&p, label, sizeof(label));
+                        r = dns_label_unescape(&p, label, sizeof label, 0);
                         if (r <= 0)
                                 return r;
                         if (r != 1)
@@ -783,7 +802,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
                         if (x < 0)
                                 return -EINVAL;
 
-                        r = dns_label_unescape(&p, label, sizeof(label));
+                        r = dns_label_unescape(&p, label, sizeof label, 0);
                         if (r <= 0)
                                 return r;
                         if (r != 1)
@@ -851,7 +870,7 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
                  * dns_label_unescape() returns 0 when it hits the end
                  * of the domain name, which we rely on here to encode
                  * the trailing NUL byte. */
-                r = dns_label_unescape(&domain, (char *) out, len);
+                r = dns_label_unescape(&domain, (char *) out, len, 0);
                 if (r < 0)
                         return r;
 
@@ -918,7 +937,7 @@ bool dns_srv_type_is_valid(const char *name) {
 
                 /* This more or less implements RFC 6335, Section 5.1 */
 
-                r = dns_label_unescape(&name, label, sizeof(label));
+                r = dns_label_unescape(&name, label, sizeof label, 0);
                 if (r < 0)
                         return false;
                 if (r == 0)
@@ -978,7 +997,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
                 return -EINVAL;
 
         if (!name)
-                return dns_name_concat(type, domain, ret);
+                return dns_name_concat(type, domain, 0, ret);
 
         if (!dns_service_name_is_valid(name))
                 return -EINVAL;
@@ -987,11 +1006,11 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
         if (r < 0)
                 return r;
 
-        r = dns_name_concat(type, domain, &n);
+        r = dns_name_concat(type, domain, 0, &n);
         if (r < 0)
                 return r;
 
-        return dns_name_concat(escaped, n, ret);
+        return dns_name_concat(escaped, n, 0, ret);
 }
 
 static bool dns_service_name_label_is_valid(const char *label, size_t n) {
@@ -1016,7 +1035,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
         assert(joined);
 
         /* Get first label from the full name */
-        an = dns_label_unescape(&p, a, sizeof(a));
+        an = dns_label_unescape(&p, a, sizeof(a), 0);
         if (an < 0)
                 return an;
 
@@ -1024,7 +1043,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
                 x++;
 
                 /* If there was a first label, try to get the second one */
-                bn = dns_label_unescape(&p, b, sizeof(b));
+                bn = dns_label_unescape(&p, b, sizeof(b), 0);
                 if (bn < 0)
                         return bn;
 
@@ -1033,7 +1052,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
 
                         /* If there was a second label, try to get the third one */
                         q = p;
-                        cn = dns_label_unescape(&p, c, sizeof(c));
+                        cn = dns_label_unescape(&p, c, sizeof(c), 0);
                         if (cn < 0)
                                 return cn;
 
@@ -1083,7 +1102,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
         d = joined;
 
 finish:
-        r = dns_name_normalize(d, &domain);
+        r = dns_name_normalize(d, 0, &domain);
         if (r < 0)
                 return r;
 
@@ -1099,7 +1118,7 @@ finish:
         return 0;
 }
 
-static int dns_name_build_suffix_table(const char *name, const char*table[]) {
+static int dns_name_build_suffix_table(const char *name, const char *table[]) {
         const char *p;
         unsigned n = 0;
         int r;
@@ -1228,12 +1247,12 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
                 }
 
                 x = a_labels[n - 1 - k];
-                r = dns_label_unescape(&x, la, sizeof(la));
+                r = dns_label_unescape(&x, la, sizeof la, 0);
                 if (r < 0)
                         return r;
 
                 y = b_labels[m - 1 - k];
-                q = dns_label_unescape(&y, lb, sizeof(lb));
+                q = dns_label_unescape(&y, lb, sizeof lb, 0);
                 if (q < 0)
                         return q;
 
@@ -1301,13 +1320,13 @@ int dns_name_apply_idna(const char *name, char **ret) {
         for (;;) {
                 char label[DNS_LABEL_MAX];
 
-                r = dns_label_unescape(&name, label, sizeof(label));
+                r = dns_label_unescape(&name, label, sizeof label, 0);
                 if (r < 0)
                         return r;
                 if (r == 0)
                         break;
 
-                q = dns_label_apply_idna(label, r, label, sizeof(label));
+                q = dns_label_apply_idna(label, r, label, sizeof label);
                 if (q < 0)
                         return q;
                 if (q > 0)
index 1e9b57059b89d2c2676c0f0bff3b072fe007bfe6..6ed512c6b1656515c3a17b99fe994e6baedcf84e 100644 (file)
 /* Maximum number of labels per valid hostname */
 #define DNS_N_LABELS_MAX 127
 
-int dns_label_unescape(const char **name, char *dest, size_t sz);
+typedef enum DNSLabelFlags {
+        DNS_LABEL_LDH        = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
+        DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */
+} DNSLabelFlags;
+
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
 int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
 int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
 int dns_label_escape_new(const char *p, size_t l, char **ret);
 
 static inline int dns_name_parent(const char **name) {
-        return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
+        return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0);
 }
 
 #if HAVE_LIBIDN
@@ -38,18 +43,29 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
 int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
 #endif
 
-int dns_name_concat(const char *a, const char *b, char **ret);
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret);
 
-static inline int dns_name_normalize(const char *s, char **ret) {
+static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) {
         /* dns_name_concat() normalizes as a side-effect */
-        return dns_name_concat(s, NULL, ret);
+        return dns_name_concat(s, NULL, flags, ret);
 }
 
 static inline int dns_name_is_valid(const char *s) {
         int r;
 
         /* dns_name_normalize() verifies as a side effect */
-        r = dns_name_normalize(s, NULL);
+        r = dns_name_normalize(s, 0, NULL);
+        if (r == -EINVAL)
+                return 0;
+        if (r < 0)
+                return r;
+        return 1;
+}
+
+static inline int dns_name_is_valid_ldh(const char *s) {
+        int r;
+
+        r = dns_name_concat(s, NULL, DNS_LABEL_LDH|DNS_LABEL_NO_ESCAPES, NULL);
         if (r == -EINVAL)
                 return 0;
         if (r < 0)
@@ -57,8 +73,8 @@ static inline int dns_name_is_valid(const char *s) {
         return 1;
 }
 
-void dns_name_hash_func(const void *s, struct siphash *state);
-int dns_name_compare_func(const void *a, const void *b);
+void dns_name_hash_func(const char *s, struct siphash *state);
+int dns_name_compare_func(const char *a, const char *b);
 extern const struct hash_ops dns_name_hash_ops;
 
 int dns_name_between(const char *a, const char *b, const char *c);
diff --git a/src/shared/env-file-label.c b/src/shared/env-file-label.c
new file mode 100644 (file)
index 0000000..add68d2
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/stat.h>
+
+#include "env-file-label.h"
+#include "env-file.h"
+#include "selinux-util.h"
+
+int write_env_file_label(const char *fname, char **l) {
+        int r;
+
+        r = mac_selinux_create_file_prepare(fname, S_IFREG);
+        if (r < 0)
+                return r;
+
+        r = write_env_file(fname, l);
+
+        mac_selinux_create_file_clear();
+
+        return r;
+}
diff --git a/src/shared/env-file-label.h b/src/shared/env-file-label.h
new file mode 100644 (file)
index 0000000..158fc4e
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+/* These functions are split out of fileio.h (and not for example just flags to the functions they wrap) in order to
+ * optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux, but not
+ * for all */
+
+int write_env_file_label(const char *fname, char **l);
index 10d774dfcdfbd36908abfff40295adff5ae27703..d66b3004590a12495759cb6d50167b06db27f27d 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "alloc-util.h"
 #include "conf-files.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "exec-util.h"
 #include "fd-util.h"
@@ -16,6 +17,7 @@
 #include "hashmap.h"
 #include "macro.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "serialize.h"
 #include "set.h"
 #include "signal-util.h"
@@ -23,6 +25,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 /* Put this test here for a lack of better place */
@@ -50,6 +53,8 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
                                 _exit(EXIT_FAILURE);
                 }
 
+                (void) rlimit_nofile_safe();
+
                 if (!argv) {
                         _argv[0] = (char*) path;
                         _argv[1] = NULL;
index b5362b5cbc7c53621a0515da23883842b982924f..49ab29720b1a33cee7ea349ef5d506e22ba4d4fe 100644 (file)
@@ -20,35 +20,6 @@ int write_string_file_atomic_label_ts(const char *fn, const char *line, struct t
         return r;
 }
 
-int write_env_file_label(const char *fname, char **l) {
-        int r;
-
-        r = mac_selinux_create_file_prepare(fname, S_IFREG);
-        if (r < 0)
-                return r;
-
-        r = write_env_file(fname, l);
-
-        mac_selinux_create_file_clear();
-
-        return r;
-}
-
-int fopen_temporary_label(const char *target,
-                          const char *path, FILE **f, char **temp_path) {
-        int r;
-
-        r = mac_selinux_create_file_prepare(target, S_IFREG);
-        if (r < 0)
-                return r;
-
-        r = fopen_temporary(path, f, temp_path);
-
-        mac_selinux_create_file_clear();
-
-        return r;
-}
-
 int create_shutdown_run_nologin_or_warn(void) {
         int r;
 
index d11112debd6d8c56f06babf18364c384d55497c1..8f88955d8102b7ea8d5ae637f1b058044696dbbc 100644 (file)
@@ -3,17 +3,13 @@
 
 #include <stdio.h>
 
-#include "fileio.h"
-
-/* These functions are split out of fileio.h (and not for examplement just as flags to the functions they wrap) in
- * order to optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux,
- * but not for all */
+/* These functions are split out of fileio.h (and not for example just flags to the functions they wrap) in order to
+ * optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux, but not
+ * for all */
 
 int write_string_file_atomic_label_ts(const char *fn, const char *line, struct timespec *ts);
 static inline int write_string_file_atomic_label(const char *fn, const char *line) {
         return write_string_file_atomic_label_ts(fn, line, NULL);
 }
-int write_env_file_label(const char *fname, char **l);
-int fopen_temporary_label(const char *target, const char *path, FILE **f, char **temp_path);
 
 int create_shutdown_run_nologin_or_warn(void);
index 10e15c9d709de2c90238f5fe1dc1516a9f0093e8..7d529801a1da81d56ea2c9da3dc081fa4c6ec353 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <ctype.h>
 #include <stdio_ext.h>
 
 #include "alloc-util.h"
@@ -9,6 +10,7 @@
 #include "gunicode.h"
 #include "pager.h"
 #include "parse-util.h"
+#include "pretty-print.h"
 #include "string-util.h"
 #include "terminal-util.h"
 #include "time-util.h"
@@ -57,7 +59,10 @@ typedef struct TableData {
         unsigned ellipsize_percent; /* 0 … 100, where to place the ellipsis when compression is needed */
         unsigned align_percent;     /* 0 … 100, where to pad with spaces when expanding is needed. 0: left-aligned, 100: right-aligned */
 
+        bool uppercase;             /* Uppercase string on display */
+
         const char *color;          /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */
+        char *url;                  /* A URL to use for a clickable hyperlink */
         char *formatted;            /* A cached textual representation of the cell data, before ellipsation/alignment */
 
         union {
@@ -68,6 +73,8 @@ typedef struct TableData {
                 uint64_t size;
                 char string[0];
                 uint32_t uint32;
+                uint64_t uint64;
+                int percent;        /* we use 'int' as datatype for percent values in order to match the result of parse_percent() */
                 /* … add more here as we start supporting more cell data types … */
         };
 } TableData;
@@ -103,6 +110,8 @@ struct Table {
 
         size_t *sort_map;     /* The columns to order rows by, in order of preference. */
         size_t n_sort_map;
+
+        bool *reverse_map;
 };
 
 Table *table_new_raw(size_t n_columns) {
@@ -126,6 +135,7 @@ Table *table_new_raw(size_t n_columns) {
 Table *table_new_internal(const char *first_header, ...) {
         _cleanup_(table_unrefp) Table *t = NULL;
         size_t n_columns = 1;
+        const char *h;
         va_list ap;
         int r;
 
@@ -133,8 +143,6 @@ Table *table_new_internal(const char *first_header, ...) {
 
         va_start(ap, first_header);
         for (;;) {
-                const char *h;
-
                 h = va_arg(ap, const char*);
                 if (!h)
                         break;
@@ -147,19 +155,18 @@ Table *table_new_internal(const char *first_header, ...) {
         if (!t)
                 return NULL;
 
-        r = table_add_cell(t, NULL, TABLE_STRING, first_header);
-        if (r < 0)
-                return NULL;
-
         va_start(ap, first_header);
-        for (;;) {
-                const char *h;
+        for (h = first_header; h; h = va_arg(ap, const char*)) {
+                TableCell *cell;
 
-                h = va_arg(ap, const char*);
-                if (!h)
-                        break;
+                r = table_add_cell(t, &cell, TABLE_STRING, h);
+                if (r < 0) {
+                        va_end(ap);
+                        return NULL;
+                }
 
-                r = table_add_cell(t, NULL, TABLE_STRING, h);
+                /* Make the table header uppercase */
+                r = table_set_uppercase(t, cell, true);
                 if (r < 0) {
                         va_end(ap);
                         return NULL;
@@ -175,6 +182,8 @@ static TableData *table_data_free(TableData *d) {
         assert(d);
 
         free(d->formatted);
+        free(d->url);
+
         return mfree(d);
 }
 
@@ -193,6 +202,7 @@ Table *table_unref(Table *t) {
         free(t->data);
         free(t->display_map);
         free(t->sort_map);
+        free(t->reverse_map);
 
         return mfree(t);
 }
@@ -215,11 +225,15 @@ static size_t table_data_size(TableDataType type, const void *data) {
                 return sizeof(usec_t);
 
         case TABLE_SIZE:
+        case TABLE_UINT64:
                 return sizeof(uint64_t);
 
         case TABLE_UINT32:
                 return sizeof(uint32_t);
 
+        case TABLE_PERCENT:
+                return sizeof(int);
+
         default:
                 assert_not_reached("Uh? Unexpected cell type");
         }
@@ -256,13 +270,21 @@ static bool table_data_matches(
         if (d->ellipsize_percent != ellipsize_percent)
                 return false;
 
+        /* If a color/url/uppercase flag is set, refuse to merge */
+        if (d->color)
+                return false;
+        if (d->url)
+                return false;
+        if (d->uppercase)
+                return false;
+
         k = table_data_size(type, data);
         l = table_data_size(d->type, d->data);
 
         if (k != l)
                 return false;
 
-        return memcmp(data, d->data, l) == 0;
+        return memcmp_safe(data, d->data, l) == 0;
 }
 
 static TableData *table_data_new(
@@ -376,6 +398,7 @@ int table_dup_cell(Table *t, TableCell *cell) {
 }
 
 static int table_dedup_cell(Table *t, TableCell *cell) {
+        _cleanup_free_ char *curl = NULL;
         TableData *nd, *od;
         size_t i;
 
@@ -394,10 +417,27 @@ static int table_dedup_cell(Table *t, TableCell *cell) {
 
         assert(od->n_ref > 1);
 
-        nd = table_data_new(od->type, od->data, od->minimum_width, od->maximum_width, od->weight, od->align_percent, od->ellipsize_percent);
+        if (od->url) {
+                curl = strdup(od->url);
+                if (!curl)
+                        return -ENOMEM;
+        }
+
+        nd = table_data_new(
+                        od->type,
+                        od->data,
+                        od->minimum_width,
+                        od->maximum_width,
+                        od->weight,
+                        od->align_percent,
+                        od->ellipsize_percent);
         if (!nd)
                 return -ENOMEM;
 
+        nd->color = od->color;
+        nd->url = TAKE_PTR(curl);
+        nd->uppercase = od->uppercase;
+
         table_data_unref(od);
         t->data[i] = nd;
 
@@ -524,6 +564,88 @@ int table_set_color(Table *t, TableCell *cell, const char *color) {
         return 0;
 }
 
+int table_set_url(Table *t, TableCell *cell, const char *url) {
+        _cleanup_free_ char *copy = NULL;
+        int r;
+
+        assert(t);
+        assert(cell);
+
+        if (url) {
+                copy = strdup(url);
+                if (!copy)
+                        return -ENOMEM;
+        }
+
+        r = table_dedup_cell(t, cell);
+        if (r < 0)
+                return r;
+
+        return free_and_replace(table_get_data(t, cell)->url, copy);
+}
+
+int table_set_uppercase(Table *t, TableCell *cell, bool b) {
+        TableData *d;
+        int r;
+
+        assert(t);
+        assert(cell);
+
+        r = table_dedup_cell(t, cell);
+        if (r < 0)
+                return r;
+
+        assert_se(d = table_get_data(t, cell));
+
+        if (d->uppercase == b)
+                return 0;
+
+        d->formatted = mfree(d->formatted);
+        d->uppercase = b;
+        return 1;
+}
+
+int table_update(Table *t, TableCell *cell, TableDataType type, const void *data) {
+        _cleanup_free_ char *curl = NULL;
+        TableData *nd, *od;
+        size_t i;
+
+        assert(t);
+        assert(cell);
+
+        i = TABLE_CELL_TO_INDEX(cell);
+        if (i >= t->n_cells)
+                return -ENXIO;
+
+        assert_se(od = t->data[i]);
+
+        if (od->url) {
+                curl = strdup(od->url);
+                if (!curl)
+                        return -ENOMEM;
+        }
+
+        nd = table_data_new(
+                        type,
+                        data,
+                        od->minimum_width,
+                        od->maximum_width,
+                        od->weight,
+                        od->align_percent,
+                        od->ellipsize_percent);
+        if (!nd)
+                return -ENOMEM;
+
+        nd->color = od->color;
+        nd->url = TAKE_PTR(curl);
+        nd->uppercase = od->uppercase;
+
+        table_data_unref(od);
+        t->data[i] = nd;
+
+        return 0;
+}
+
 int table_add_many_internal(Table *t, TableDataType first_type, ...) {
         TableDataType type;
         va_list ap;
@@ -542,6 +664,8 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         uint64_t size;
                         usec_t usec;
                         uint32_t uint32;
+                        uint64_t uint64;
+                        int percent;
                         bool b;
                 } buffer;
 
@@ -576,6 +700,16 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         data = &buffer.uint32;
                         break;
 
+                case TABLE_UINT64:
+                        buffer.uint64 = va_arg(ap, uint64_t);
+                        data = &buffer.uint64;
+                        break;
+
+                case TABLE_PERCENT:
+                        buffer.percent = va_arg(ap, int);
+                        data = &buffer.percent;
+                        break;
+
                 case _TABLE_DATA_TYPE_MAX:
                         /* Used as end marker */
                         va_end(ap);
@@ -699,6 +833,12 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
                 case TABLE_UINT32:
                         return CMP(a->uint32, b->uint32);
 
+                case TABLE_UINT64:
+                        return CMP(a->uint64, b->uint64);
+
+                case TABLE_PERCENT:
+                        return CMP(a->percent, b->percent);
+
                 default:
                         ;
                 }
@@ -732,7 +872,7 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
 
                 r = cell_data_compare(d, *a, dd, *b);
                 if (r != 0)
-                        return r;
+                        return t->reverse_map && t->reverse_map[t->sort_map[i]] ? -r : r;
         }
 
         /* Order identical lines by the order there were originally added in */
@@ -750,6 +890,20 @@ static const char *table_data_format(TableData *d) {
                 return "";
 
         case TABLE_STRING:
+                if (d->uppercase) {
+                        char *p, *q;
+
+                        d->formatted = new(char, strlen(d->string) + 1);
+                        if (!d->formatted)
+                                return NULL;
+
+                        for (p = d->string, q = d->formatted; *p; p++, q++)
+                                *q = (char) toupper((unsigned char) *p);
+                        *q = 0;
+
+                        return d->formatted;
+                }
+
                 return d->string;
 
         case TABLE_BOOLEAN:
@@ -776,7 +930,7 @@ static const char *table_data_format(TableData *d) {
                 if (!p)
                         return NULL;
 
-                if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timestamp, 0))
+                if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timespan, 0))
                         return "n/a";
 
                 d->formatted = TAKE_PTR(p);
@@ -809,6 +963,30 @@ static const char *table_data_format(TableData *d) {
                 break;
         }
 
+        case TABLE_UINT64: {
+                _cleanup_free_ char *p;
+
+                p = new(char, DECIMAL_STR_WIDTH(d->uint64) + 1);
+                if (!p)
+                        return NULL;
+
+                sprintf(p, "%" PRIu64, d->uint64);
+                d->formatted = TAKE_PTR(p);
+                break;
+        }
+
+        case TABLE_PERCENT: {
+                _cleanup_free_ char *p;
+
+                p = new(char, DECIMAL_STR_WIDTH(d->percent) + 2);
+                if (!p)
+                        return NULL;
+
+                sprintf(p, "%i%%" , d->percent);
+                d->formatted = TAKE_PTR(p);
+                break;
+        }
+
         default:
                 assert_not_reached("Unexpected type?");
         }
@@ -838,11 +1016,13 @@ static int table_data_requested_width(TableData *d, size_t *ret) {
         return 0;
 }
 
-static char *align_string_mem(const char *str, size_t new_length, unsigned percent) {
-        size_t w = 0, space, lspace, old_length;
+static char *align_string_mem(const char *str, const char *url, size_t new_length, unsigned percent) {
+        size_t w = 0, space, lspace, old_length, clickable_length;
+        _cleanup_free_ char *clickable = NULL;
         const char *p;
         char *ret;
         size_t i;
+        int r;
 
         /* As with ellipsize_mem(), 'old_length' is a byte size while 'new_length' is a width in character cells */
 
@@ -851,6 +1031,15 @@ static char *align_string_mem(const char *str, size_t new_length, unsigned perce
 
         old_length = strlen(str);
 
+        if (url) {
+                r = terminal_urlify(url, str, &clickable);
+                if (r < 0)
+                        return NULL;
+
+                clickable_length = strlen(clickable);
+        } else
+                clickable_length = old_length;
+
         /* Determine current width on screen */
         p = str;
         while (p < str + old_length) {
@@ -867,23 +1056,23 @@ static char *align_string_mem(const char *str, size_t new_length, unsigned perce
 
         /* Already wider than the target, if so, don't do anything */
         if (w >= new_length)
-                return strndup(str, old_length);
+                return clickable ? TAKE_PTR(clickable) : strdup(str);
 
         /* How much spaces shall we add? An how much on the left side? */
         space = new_length - w;
         lspace = space * percent / 100U;
 
-        ret = new(char, space + old_length + 1);
+        ret = new(char, space + clickable_length + 1);
         if (!ret)
                 return NULL;
 
         for (i = 0; i < lspace; i++)
                 ret[i] = ' ';
-        memcpy(ret + lspace, str, old_length);
-        for (i = lspace + old_length; i < space + old_length; i++)
+        memcpy(ret + lspace, clickable ?: str, clickable_length);
+        for (i = lspace + clickable_length; i < space + clickable_length; i++)
                 ret[i] = ' ';
 
-        ret[space + old_length] = 0;
+        ret[space + clickable_length] = 0;
         return ret;
 }
 
@@ -1136,23 +1325,41 @@ int table_print(Table *t, FILE *f) {
                         } else if (l < width[j]) {
                                 /* Field is shorter than allocated space. Let's align with spaces */
 
-                                buffer = align_string_mem(field, width[j], d->align_percent);
+                                buffer = align_string_mem(field, d->url, width[j], d->align_percent);
                                 if (!buffer)
                                         return -ENOMEM;
 
                                 field = buffer;
                         }
 
+                        if (l >= width[j] && d->url) {
+                                _cleanup_free_ char *clickable = NULL;
+
+                                r = terminal_urlify(d->url, field, &clickable);
+                                if (r < 0)
+                                        return r;
+
+                                free_and_replace(buffer, clickable);
+                                field = buffer;
+                        }
+
+                        if (row == t->data) /* underline header line fully, including the column separator */
+                                fputs(ansi_underline(), f);
+
                         if (j > 0)
                                 fputc(' ', f); /* column separator */
 
-                        if (d->color)
+                        if (d->color && colors_enabled()) {
+                                if (row == t->data) /* first undo header underliner */
+                                        fputs(ANSI_NORMAL, f);
+
                                 fputs(d->color, f);
+                        }
 
                         fputs(field, f);
 
-                        if (d->color)
-                                fputs(ansi_normal(), f);
+                        if (colors_enabled() && (d->color || row == t->data))
+                                fputs(ANSI_NORMAL, f);
                 }
 
                 fputc('\n', f);
@@ -1199,3 +1406,220 @@ size_t table_get_columns(Table *t) {
         assert(t->n_columns > 0);
         return t->n_columns;
 }
+
+int table_set_reverse(Table *t, size_t column, bool b) {
+        assert(t);
+        assert(column < t->n_columns);
+
+        if (!t->reverse_map) {
+                if (!b)
+                        return 0;
+
+                t->reverse_map = new0(bool, t->n_columns);
+                if (!t->reverse_map)
+                        return -ENOMEM;
+        }
+
+        t->reverse_map[column] = b;
+        return 0;
+}
+
+TableCell *table_get_cell(Table *t, size_t row, size_t column) {
+        size_t i;
+
+        assert(t);
+
+        if (column >= t->n_columns)
+                return NULL;
+
+        i = row * t->n_columns + column;
+        if (i >= t->n_cells)
+                return NULL;
+
+        return TABLE_INDEX_TO_CELL(i);
+}
+
+const void *table_get(Table *t, TableCell *cell) {
+        TableData *d;
+
+        assert(t);
+
+        d = table_get_data(t, cell);
+        if (!d)
+                return NULL;
+
+        return d->data;
+}
+
+const void* table_get_at(Table *t, size_t row, size_t column) {
+        TableCell *cell;
+
+        cell = table_get_cell(t, row, column);
+        if (!cell)
+                return NULL;
+
+        return table_get(t, cell);
+}
+
+static int table_data_to_json(TableData *d, JsonVariant **ret) {
+
+        switch (d->type) {
+
+        case TABLE_EMPTY:
+                return json_variant_new_null(ret);
+
+        case TABLE_STRING:
+                return json_variant_new_string(ret, d->string);
+
+        case TABLE_BOOLEAN:
+                return json_variant_new_boolean(ret, d->boolean);
+
+        case TABLE_TIMESTAMP:
+                if (d->timestamp == USEC_INFINITY)
+                        return json_variant_new_null(ret);
+
+                return json_variant_new_unsigned(ret, d->timestamp);
+
+        case TABLE_TIMESPAN:
+                if (d->timespan == USEC_INFINITY)
+                        return json_variant_new_null(ret);
+
+                return json_variant_new_unsigned(ret, d->timespan);
+
+        case TABLE_SIZE:
+                if (d->size == (size_t) -1)
+                        return json_variant_new_null(ret);
+
+                return json_variant_new_unsigned(ret, d->size);
+
+        case TABLE_UINT32:
+                return json_variant_new_unsigned(ret, d->uint32);
+
+        case TABLE_UINT64:
+                return json_variant_new_unsigned(ret, d->uint64);
+
+        case TABLE_PERCENT:
+                return json_variant_new_integer(ret, d->percent);
+
+        default:
+                return -EINVAL;
+        }
+}
+
+int table_to_json(Table *t, JsonVariant **ret) {
+        JsonVariant **rows = NULL, **elements = NULL;
+        _cleanup_free_ size_t *sorted = NULL;
+        size_t n_rows, i, j, display_columns;
+        int r;
+
+        assert(t);
+
+        /* Ensure we have no incomplete rows */
+        assert(t->n_cells % t->n_columns == 0);
+
+        n_rows = t->n_cells / t->n_columns;
+        assert(n_rows > 0); /* at least the header row must be complete */
+
+        if (t->sort_map) {
+                /* If sorting is requested, let's calculate an index table we use to lookup the actual index to display with. */
+
+                sorted = new(size_t, n_rows);
+                if (!sorted) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                for (i = 0; i < n_rows; i++)
+                        sorted[i] = i * t->n_columns;
+
+                typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
+        }
+
+        if (t->display_map)
+                display_columns = t->n_display_map;
+        else
+                display_columns = t->n_columns;
+        assert(display_columns > 0);
+
+        elements = new0(JsonVariant*, display_columns * 2);
+        if (!elements) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        for (j = 0; j < display_columns; j++) {
+                TableData *d;
+
+                assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
+
+                r = table_data_to_json(d, elements + j*2);
+                if (r < 0)
+                        goto finish;
+        }
+
+        rows = new0(JsonVariant*, n_rows-1);
+        if (!rows) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        for (i = 1; i < n_rows; i++) {
+                TableData **row;
+
+                if (sorted)
+                        row = t->data + sorted[i];
+                else
+                        row = t->data + i * t->n_columns;
+
+                for (j = 0; j < display_columns; j++) {
+                        TableData *d;
+                        size_t k;
+
+                        assert_se(d = row[t->display_map ? t->display_map[j] : j]);
+
+                        k = j*2+1;
+                        elements[k] = json_variant_unref(elements[k]);
+
+                        r = table_data_to_json(d, elements + k);
+                        if (r < 0)
+                                goto finish;
+                }
+
+                r = json_variant_new_object(rows + i - 1, elements, display_columns * 2);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = json_variant_new_array(ret, rows, n_rows - 1);
+
+finish:
+        if (rows) {
+                json_variant_unref_many(rows, n_rows-1);
+                free(rows);
+        }
+
+        if (elements) {
+                json_variant_unref_many(elements, display_columns*2);
+                free(elements);
+        }
+
+        return r;
+}
+
+int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) {
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+        int r;
+
+        assert(t);
+
+        if (!f)
+                f = stdout;
+
+        r = table_to_json(t, &v);
+        if (r < 0)
+                return r;
+
+        json_variant_dump(v, flags, f, NULL);
+
+        return fflush_and_check(f);
+}
index 6dc2d160521716fbef11ad4d18f1ce71ea694f37..5ff247953b5f2cb653812c8c421fe2c1d9f3d145 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 
+#include "json.h"
 #include "macro.h"
 
 typedef enum TableDataType {
@@ -15,6 +16,8 @@ typedef enum TableDataType {
         TABLE_TIMESPAN,
         TABLE_SIZE,
         TABLE_UINT32,
+        TABLE_UINT64,
+        TABLE_PERCENT,
         _TABLE_DATA_TYPE_MAX,
         _TABLE_DATA_TYPE_INVALID = -1,
 } TableDataType;
@@ -42,6 +45,10 @@ int table_set_weight(Table *t, TableCell *cell, unsigned weight);
 int table_set_align_percent(Table *t, TableCell *cell, unsigned percent);
 int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent);
 int table_set_color(Table *t, TableCell *cell, const char *color);
+int table_set_url(Table *t, TableCell *cell, const char *color);
+int table_set_uppercase(Table *t, TableCell *cell, bool b);
+
+int table_update(Table *t, TableCell *cell, TableDataType type, const void *data);
 
 int table_add_many_internal(Table *t, TableDataType first_type, ...);
 #define table_add_many(t, ...) table_add_many_internal(t, __VA_ARGS__, _TABLE_DATA_TYPE_MAX)
@@ -50,6 +57,7 @@ void table_set_header(Table *table, bool b);
 void table_set_width(Table *t, size_t width);
 int table_set_display(Table *t, size_t first_column, ...);
 int table_set_sort(Table *t, size_t first_column, ...);
+int table_set_reverse(Table *t, size_t column, bool b);
 
 int table_print(Table *t, FILE *f);
 int table_format(Table *t, char **ret);
@@ -60,3 +68,11 @@ static inline TableCell* TABLE_HEADER_CELL(size_t i) {
 
 size_t table_get_rows(Table *t);
 size_t table_get_columns(Table *t);
+
+TableCell *table_get_cell(Table *t, size_t row, size_t column);
+
+const void *table_get(Table *t, TableCell *cell);
+const void *table_get_at(Table *t, size_t row, size_t column);
+
+int table_to_json(Table *t, JsonVariant **ret);
+int table_print_json(Table *t, FILE *f, unsigned json_flags);
index 13591ac892466d744029d1fadc2e9ec2ca700b52..0adaaf2c5671d161fe43d9174b16a6db02490388 100644 (file)
@@ -197,10 +197,9 @@ int generator_write_timeouts(
                 const char *opts,
                 char **filtered) {
 
-        /* Allow configuration how long we wait for a device that
-         * backs a mount point to show up. This is useful to support
-         * endless device timeouts for devices that show up only after
-         * user input, like crypto devices. */
+        /* Configure how long we wait for a device that backs a mount point or a
+         * swap partition to show up. This is useful to support endless device timeouts
+         * for devices that show up only after user input, like crypto devices. */
 
         _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
         usec_t u;
index d53b90796faa7fa42e00bd757d18c449d20f316d..bcd6c0c5ea17554865dfb9c6b2fd4f7527ca4edc 100644 (file)
@@ -160,7 +160,7 @@ int import_assign_pool_quota_and_warn(const char *path) {
         if (r < 0)
                 return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
         if (r > 0)
-                log_info("Set up default quota hierarchy for %s.", path);
+                log_debug("Set up default quota hierarchy for %s.", path);
 
         return 0;
 }
index 28e07a23a55b9ee15e4a201480f9dc98851edb65..d172162a3c3121e74defa18a0772df920a439f43 100644 (file)
@@ -1464,7 +1464,7 @@ static int unit_file_search(
         STRV_FOREACH(p, paths->search_path) {
                 char *path;
 
-                path = path_join(NULL, *p, dropin_dir_name);
+                path = path_join(*p, dropin_dir_name);
                 if (!path)
                         return -ENOMEM;
 
@@ -1478,7 +1478,7 @@ static int unit_file_search(
                 STRV_FOREACH(p, paths->search_path) {
                         char *path;
 
-                        path = path_join(NULL, *p, dropin_template_dir_name);
+                        path = path_join(*p, dropin_template_dir_name);
                         if (!path)
                                 return -ENOMEM;
 
diff --git a/src/shared/ip-protocol-list.c b/src/shared/ip-protocol-list.c
new file mode 100644 (file)
index 0000000..aa675ea
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <netinet/in.h>
+
+#include "alloc-util.h"
+#include "ip-protocol-list.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+static const struct ip_protocol_name* lookup_ip_protocol(register const char *str, register GPERF_LEN_TYPE len);
+
+#include "ip-protocol-from-name.h"
+#include "ip-protocol-to-name.h"
+
+const char *ip_protocol_to_name(int id) {
+
+        if (id < 0)
+                return NULL;
+
+        if ((size_t) id >= ELEMENTSOF(ip_protocol_names))
+                return NULL;
+
+        return ip_protocol_names[id];
+}
+
+int ip_protocol_from_name(const char *name) {
+        const struct ip_protocol_name *sc;
+
+        assert(name);
+
+        sc = lookup_ip_protocol(name, strlen(name));
+        if (!sc)
+                return -EINVAL;
+
+        return sc->id;
+}
+
+int parse_ip_protocol(const char *s) {
+        _cleanup_free_ char *str = NULL;
+        int i, r;
+
+        assert(s);
+
+        if (isempty(s))
+                return IPPROTO_IP;
+
+        /* Do not use strdupa() here, as the input string may come from *
+         * command line or config files. */
+        str = strdup(s);
+        if (!str)
+                return -ENOMEM;
+
+        i = ip_protocol_from_name(ascii_strlower(str));
+        if (i >= 0)
+                return i;
+
+        r = safe_atoi(str, &i);
+        if (r < 0)
+                return r;
+
+        if (!ip_protocol_to_name(i))
+                return -EINVAL;
+
+        return i;
+}
diff --git a/src/shared/ip-protocol-list.h b/src/shared/ip-protocol-list.h
new file mode 100644 (file)
index 0000000..5c94969
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+const char *ip_protocol_to_name(int id);
+int ip_protocol_from_name(const char *name);
+int parse_ip_protocol(const char *s);
similarity index 62%
rename from src/shared/socket-protocol-to-name.awk
rename to src/shared/ip-protocol-to-name.awk
index 4848a7631a86e908bf702726ce1242ed95423b29..824f811f5ca4071e87adfc1c50d915ac331074b8 100644 (file)
@@ -1,5 +1,5 @@
 BEGIN{
-        print "static const char* const socket_protocol_names[] = { "
+        print "static const char* const ip_protocol_names[] = { "
 }
 !/HOPOPTS/ {
         printf "        [IPPROTO_%s] = \"%s\",\n", $1, tolower($1)
index 420555ae544251129b1a5fa4bedf77a8d6f2a78c..c410b620084eebc1b543b14e32e5bf6f20b69cf7 100644 (file)
@@ -1236,7 +1236,7 @@ int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *r
         return 0;
 }
 
-static int print_source(FILE *f, JsonVariant *v, unsigned flags, bool whitespace) {
+static int print_source(FILE *f, JsonVariant *v, JsonFormatFlags flags, bool whitespace) {
         size_t w, k;
 
         if (!FLAGS_SET(flags, JSON_FORMAT_SOURCE|JSON_FORMAT_PRETTY))
@@ -1289,7 +1289,7 @@ static int print_source(FILE *f, JsonVariant *v, unsigned flags, bool whitespace
         return 0;
 }
 
-static int json_format(FILE *f, JsonVariant *v, unsigned flags, const char *prefix) {
+static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const char *prefix) {
         int r;
 
         assert(f);
@@ -1546,7 +1546,7 @@ static int json_format(FILE *f, JsonVariant *v, unsigned flags, const char *pref
         return 0;
 }
 
-int json_variant_format(JsonVariant *v, unsigned flags, char **ret) {
+int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
         _cleanup_free_ char *s = NULL;
         size_t sz = 0;
         int r;
@@ -1576,7 +1576,7 @@ int json_variant_format(JsonVariant *v, unsigned flags, char **ret) {
         return (int) sz;
 }
 
-void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *prefix) {
+void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
         if (!v)
                 return;
 
@@ -1585,6 +1585,9 @@ void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *pref
 
         print_source(f, v, flags, false);
 
+        if (((flags & (JSON_FORMAT_COLOR_AUTO|JSON_FORMAT_COLOR)) == JSON_FORMAT_COLOR_AUTO) && colors_enabled())
+                flags |= JSON_FORMAT_COLOR;
+
         if (flags & JSON_FORMAT_SSE)
                 fputs("data: ", f);
         if (flags & JSON_FORMAT_SEQ)
index 278ff77d30356e7a222df23f7cbb2049a70d39d6..4eba91c27204d39952eb7bc726aa50ef36cf9363 100644 (file)
@@ -150,17 +150,18 @@ struct json_variant_foreach_state {
 
 int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
 
-enum {
-        JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
-        JSON_FORMAT_PRETTY  = 1 << 1, /* add internal whitespace to appeal to human readers */
-        JSON_FORMAT_COLOR   = 1 << 2, /* insert ANSI color sequences */
-        JSON_FORMAT_SOURCE  = 1 << 3, /* prefix with source filename/line/column */
-        JSON_FORMAT_SSE     = 1 << 4, /* prefix/suffix with W3C server-sent events */
-        JSON_FORMAT_SEQ     = 1 << 5, /* prefix/suffix with RFC 7464 application/json-seq */
-};
-
-int json_variant_format(JsonVariant *v, unsigned flags, char **ret);
-void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *prefix);
+typedef enum JsonFormatFlags {
+        JSON_FORMAT_NEWLINE    = 1 << 0, /* suffix with newline */
+        JSON_FORMAT_PRETTY     = 1 << 1, /* add internal whitespace to appeal to human readers */
+        JSON_FORMAT_COLOR      = 1 << 2, /* insert ANSI color sequences */
+        JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insetr ANSI color sequences if colors_enabled() says so */
+        JSON_FORMAT_SOURCE     = 1 << 4, /* prefix with source filename/line/column */
+        JSON_FORMAT_SSE        = 1 << 5, /* prefix/suffix with W3C server-sent events */
+        JSON_FORMAT_SEQ        = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
+} JsonFormatFlags;
+
+int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
+void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
 
 int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
 int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
@@ -274,9 +275,9 @@ int json_log_internal(JsonVariant *variant, int level, int error, const char *fi
 
 #define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
 
-#define _JSON_VARIANT_STRING_CONST(xq, x)                                       \
+#define _JSON_VARIANT_STRING_CONST(xq, x)                               \
         ({                                                              \
-                __attribute__((__aligned__(2))) static const char UNIQ_T(json_string_const, xq)[] = (x); \
+                _align_(2) static const char UNIQ_T(json_string_const, xq)[] = (x); \
                 assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \
                 (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
         })
index c2abd9956f2d51cd3c2f34f3857322e53d4c127f..e0eef34cdc6d0680cee93f2cd804e14515a01391 100644 (file)
@@ -1,11 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <stddef.h>
-
-#include "macro.h"
-#include "missing.h"
-
 typedef struct LockFile {
         char *path;
         int fd;
index 41d484fa16f0e40bef0cd130658d9a263c202664..525a948f3609fc1ee9c2044577e3783b78cb3f7d 100644 (file)
@@ -171,6 +171,10 @@ static bool print_multiline(
                         color_on = ANSI_HIGHLIGHT;
                         color_off = ANSI_NORMAL;
                         highlight_on = ANSI_HIGHLIGHT_RED;
+                } else if (priority >= LOG_DEBUG) {
+                        color_on = ANSI_GREY;
+                        color_off = ANSI_NORMAL;
+                        highlight_on = ANSI_HIGHLIGHT_RED;
                 }
         }
 
@@ -946,10 +950,7 @@ static int output_json(
         }
 
         json_variant_dump(object,
-                          (mode == OUTPUT_JSON_SSE    ? JSON_FORMAT_SSE :
-                           mode == OUTPUT_JSON_SEQ    ? JSON_FORMAT_SEQ :
-                           mode == OUTPUT_JSON_PRETTY ? JSON_FORMAT_PRETTY :
-                                                        JSON_FORMAT_NEWLINE) |
+                          output_mode_to_json_format_flags(mode) |
                           (FLAGS_SET(flags, OUTPUT_COLOR) ? JSON_FORMAT_COLOR : 0),
                           f, NULL);
 
@@ -1031,7 +1032,7 @@ static int output_cat(
 
 static int (*output_funcs[_OUTPUT_MODE_MAX])(
                 FILE *f,
-                sd_journal*j,
+                sd_journal *j,
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
index d5f6ab8529a917e6d6680774d6222286fffd22f5..af06ab22e88bbb6de10cd5cb72dd8f6ad433b14d 100644 (file)
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/file.h>
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <linux/fs.h>
@@ -17,9 +18,9 @@
 #include "copy.h"
 #include "dirent-util.h"
 #include "dissect-image.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "hashmap.h"
 #include "hostname-util.h"
@@ -70,6 +71,8 @@ static Image *image_free(Image *i) {
 }
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(Image, image, image_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, string_compare_func,
+                                      Image, image_unref);
 
 static char **image_settings_path(Image *image) {
         _cleanup_strv_free_ char **l = NULL;
index 2e38522acd973072fdc0e400c619d1cbdeea0217..9fd45899c80d3a5e160ca4a2a4ee04481ba3900b 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "sd-id128.h"
+
 #include "hashmap.h"
 #include "lockfile-util.h"
 #include "macro.h"
@@ -57,12 +59,7 @@ typedef struct Image {
 Image *image_unref(Image *i);
 Image *image_ref(Image *i);
 
-static inline Hashmap* image_hashmap_free(Hashmap *map) {
-        return hashmap_free_with_destructor(map, image_unref);
-}
-
 DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, image_hashmap_free);
 
 int image_find(ImageClass class, const char *name, Image **ret);
 int image_from_path(const char *path, Image **ret);
@@ -111,3 +108,5 @@ static inline bool IMAGE_IS_HOST(const struct Image *i) {
 
         return false;
 }
+
+extern const struct hash_ops image_hash_ops;
index df56492e7b04c5aad264cc5c9b97b7a36f0910c4..de4f704252e231ceb191d4de9d49472007c2be66 100644 (file)
@@ -1,46 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
-#include <fcntl.h>
-#include <linux/loop.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
 #include <sys/statfs.h>
-#include <sys/statvfs.h>
-#include <unistd.h>
 
-#include "sd-bus-protocol.h"
-#include "sd-bus.h"
-
-#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
 #include "label.h"
-#include "lockfile-util.h"
-#include "log.h"
 #include "machine-pool.h"
-#include "macro.h"
 #include "missing.h"
-#include "mkdir.h"
-#include "mount-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "signal-util.h"
 #include "stat-util.h"
-#include "string-util.h"
-
-#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
-#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
 
 static int check_btrfs(void) {
         struct statfs sfs;
@@ -56,344 +23,24 @@ static int check_btrfs(void) {
         return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
 }
 
-static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
-        _cleanup_free_ char *tmp = NULL;
-        _cleanup_close_ int fd = -1;
-        struct statvfs ss;
-        pid_t pid = 0;
+int setup_machine_directory(sd_bus_error *error) {
         int r;
 
-        /* We want to be able to make use of btrfs-specific file
-         * system features, in particular subvolumes, reflinks and
-         * quota. Hence, if we detect that /var/lib/machines.raw is
-         * not located on btrfs, let's create a loopback file, place a
-         * btrfs file system into it, and mount it to
-         * /var/lib/machines. */
-
-        fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-        if (fd >= 0)
-                return TAKE_FD(fd);
-
-        if (errno != ENOENT)
-                return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
-
-        r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp);
-        if (r < 0)
-                return r;
-
-        (void) mkdir_p_label("/var/lib", 0755);
-        fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
-        if (fd < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
-
-        if (fstatvfs(fd, &ss) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
-                goto fail;
-        }
-
-        if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
-                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
-                goto fail;
-        }
-
-        if (ftruncate(fd, size) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
-                goto fail;
-        }
-
-        r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
-        if (r < 0) {
-                sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
-                goto fail;
-        }
-        if (r == 0) {
-
-                /* Child */
-
-                fd = safe_close(fd);
-
-                execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
-                if (errno == ENOENT)
-                        _exit(99);
-
-                _exit(EXIT_FAILURE);
-        }
-
-        r = wait_for_terminate_and_check("mkfs", pid, 0);
-        pid = 0;
-
-        if (r < 0) {
-                sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
-                goto fail;
-        }
-        if (r == 99) {
-                r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
-                goto fail;
-        }
-        if (r != EXIT_SUCCESS) {
-                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", r);
-                goto fail;
-        }
-
-        r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw");
-        if (r < 0) {
-                sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m");
-                goto fail;
-        }
-
-        return TAKE_FD(fd);
-
-fail:
-        unlink_noerrno(tmp);
-
-        if (pid > 1)
-                kill_and_sigcont(pid, SIGKILL);
-
-        return r;
-}
-
-int setup_machine_directory(uint64_t size, sd_bus_error *error) {
-        _cleanup_(release_lock_file) LockFile lock_file = LOCK_FILE_INIT;
-        struct loop_info64 info = {
-                .lo_flags = LO_FLAGS_AUTOCLEAR,
-        };
-        _cleanup_close_ int fd = -1, control = -1, loop = -1;
-        _cleanup_free_ char* loopdev = NULL;
-        char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL;
-        bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
-        char buf[FORMAT_BYTES_MAX];
-        int r, nr = -1;
-
-        /* btrfs cannot handle file systems < 16M, hence use this as minimum */
-        if (size == (uint64_t) -1)
-                size = VAR_LIB_MACHINES_SIZE_START;
-        else if (size < 16*1024*1024)
-                size = 16*1024*1024;
-
-        /* Make sure we only set the directory up once at a time */
-        r = make_lock_file("/run/systemd/machines.lock", LOCK_EX, &lock_file);
-        if (r < 0)
-                return r;
-
         r = check_btrfs();
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
-        if (r > 0) {
-                (void) btrfs_subvol_make_label("/var/lib/machines");
-
-                r = btrfs_quota_enable("/var/lib/machines", true);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
-
-                r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
-
-                return 1;
-        }
-
-        if (path_is_mount_point("/var/lib/machines", NULL, AT_SYMLINK_FOLLOW) > 0) {
-                log_debug("/var/lib/machines is already a mount point, not creating loopback file for it.");
-                return 0;
-        }
-
-        r = dir_is_populated("/var/lib/machines");
-        if (r < 0 && r != -ENOENT)
-                return r;
-        if (r > 0) {
-                log_debug("/var/log/machines is already populated, not creating loopback file for it.");
-                return 0;
-        }
-
-        r = mkfs_exists("btrfs");
         if (r == 0)
-                return sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
-        if (r < 0)
-                return r;
-
-        fd = setup_machine_raw(size, error);
-        if (fd < 0)
-                return fd;
-
-        control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
-        if (control < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
-
-        nr = ioctl(control, LOOP_CTL_GET_FREE);
-        if (nr < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
-
-        if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
-        if (loop < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
-                goto fail;
-        }
-
-        if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
-                goto fail;
-        }
-
-        if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
-                goto fail;
-        }
-
-        /* We need to make sure the new /var/lib/machines directory
-         * has an access mode of 0700 at the time it is first made
-         * available. mkfs will create it with 0755 however. Hence,
-         * let's mount the directory into an inaccessible directory
-         * below /tmp first, fix the access mode, and move it to the
-         * public place then. */
-
-        if (!mkdtemp(tmpdir)) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
-                goto fail;
-        }
-        tmpdir_made = true;
-
-        mntdir = strjoina(tmpdir, "/mnt");
-        if (mkdir(mntdir, 0700) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
-                goto fail;
-        }
-        mntdir_made = true;
-
-        if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
-                goto fail;
-        }
-        mntdir_mounted = true;
-
-        r = btrfs_quota_enable(mntdir, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to enable quota, ignoring: %m");
-
-        r = btrfs_subvol_auto_qgroup(mntdir, 0, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m");
-
-        if (chmod(mntdir, 0700) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
-                goto fail;
-        }
-
-        (void) mkdir_p_label("/var/lib/machines", 0700);
-
-        if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
-                goto fail;
-        }
-
-        (void) syncfs(fd);
-
-        log_info("Set up /var/lib/machines as btrfs loopback file system of size %s mounted on /var/lib/machines.raw.", format_bytes(buf, sizeof(buf), size));
-
-        (void) umount2(mntdir, MNT_DETACH);
-        (void) rmdir(mntdir);
-        (void) rmdir(tmpdir);
-
-        return 1;
-
-fail:
-        if (mntdir_mounted)
-                (void) umount2(mntdir, MNT_DETACH);
-
-        if (mntdir_made)
-                (void) rmdir(mntdir);
-        if (tmpdir_made)
-                (void) rmdir(tmpdir);
-
-        if (loop >= 0) {
-                (void) ioctl(loop, LOOP_CLR_FD);
-                loop = safe_close(loop);
-        }
-
-        (void) ioctl(control, LOOP_CTL_REMOVE, nr);
-
-        return r;
-}
-
-static int sync_path(const char *p) {
-        _cleanup_close_ int fd = -1;
-
-        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
-        if (fd < 0)
-                return -errno;
-
-        if (syncfs(fd) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int grow_machine_directory(void) {
-        char buf[FORMAT_BYTES_MAX];
-        struct statvfs a, b;
-        uint64_t old_size, new_size, max_add;
-        int r;
-
-        /* Ensure the disk space data is accurate */
-        sync_path("/var/lib/machines");
-        sync_path("/var/lib/machines.raw");
-
-        if (statvfs("/var/lib/machines.raw", &a) < 0)
-                return -errno;
-
-        if (statvfs("/var/lib/machines", &b) < 0)
-                return -errno;
-
-        /* Don't grow if not enough disk space is available on the host */
-        if (((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) <= VAR_LIB_MACHINES_FREE_MIN)
-                return 0;
-
-        /* Don't grow if at least 1/3th of the fs is still free */
-        if (b.f_bavail > b.f_blocks / 3)
                 return 0;
 
-        /* Calculate how much we are willing to add at most */
-        max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN;
-
-        /* Calculate the old size */
-        old_size = (uint64_t) b.f_blocks * (uint64_t) b.f_bsize;
-
-        /* Calculate the new size as three times the size of what is used right now */
-        new_size = ((uint64_t) b.f_blocks - (uint64_t) b.f_bavail) * (uint64_t) b.f_bsize * 3;
-
-        /* Always, grow at least to the start size */
-        if (new_size < VAR_LIB_MACHINES_SIZE_START)
-                new_size = VAR_LIB_MACHINES_SIZE_START;
-
-        /* If the new size is smaller than the old size, don't grow */
-        if (new_size < old_size)
-                return 0;
-
-        /* Ensure we never add more than the maximum */
-        if (new_size > old_size + max_add)
-                new_size = old_size + max_add;
-
-        r = btrfs_resize_loopback("/var/lib/machines", new_size, true);
-        if (r < 0)
-                return log_debug_errno(r, "Failed to resize loopback: %m");
-        if (r == 0)
-                return 0;
+        (void) btrfs_subvol_make_label("/var/lib/machines");
 
-        /* Also bump the quota, of both the subvolume leaf qgroup, as
-         * well as of any subtree quota group by the same id but a
-         * higher level, if it exists. */
-        r = btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
+        r = btrfs_quota_enable("/var/lib/machines", true);
         if (r < 0)
-                log_debug_errno(r, "Failed to set btrfs limit: %m");
+                log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
 
-        r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
+        r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
         if (r < 0)
-                log_debug_errno(r, "Failed to set btrfs subtree limit: %m");
+                log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
 
-        log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
         return 1;
 }
index fd09296f232cae180ac6f45dcb6c775256d48ba0..6f59a18fb69855d123397ffe8012d11ebfe34155 100644 (file)
@@ -5,8 +5,4 @@
 
 #include "sd-bus.h"
 
-/* Grow the /var/lib/machines directory after each 10MiB written */
-#define GROW_INTERVAL_BYTES (UINT64_C(10) * UINT64_C(1024) * UINT64_C(1024))
-
-int setup_machine_directory(uint64_t size, sd_bus_error *error);
-int grow_machine_directory(void);
+int setup_machine_directory(sd_bus_error *error);
index b7676b6eb97b16b99653a6c85edf1e3b0629a849..ca2e05325ee558121324f09aebb81b63ec3c99d3 100644 (file)
@@ -41,6 +41,7 @@ shared_sources = files('''
         cpu-set-util.h
         crypt-util.c
         crypt-util.h
+        daemon-util.h
         dev-setup.c
         dev-setup.h
         dissect-image.c
@@ -52,6 +53,8 @@ shared_sources = files('''
         efivars.c
         efivars.h
         enable-mempool.c
+        env-file-label.c
+        env-file-label.h
         exec-util.c
         exec-util.h
         exit-status.c
@@ -98,6 +101,8 @@ shared_sources = files('''
         machine-pool.h
         main-func.h
         module-util.h
+        mount-util.c
+        mount-util.h
         nsflags.c
         nsflags.h
         os-util.c
@@ -116,8 +121,6 @@ shared_sources = files('''
         reboot-util.h
         resolve-util.c
         resolve-util.h
-        rlimit-util.c
-        rlimit-util.h
         seccomp-util.h
         securebits-util.c
         securebits-util.h
@@ -125,8 +128,8 @@ shared_sources = files('''
         serialize.h
         sleep-config.c
         sleep-config.h
-        socket-protocol-list.c
-        socket-protocol-list.h
+        ip-protocol-list.c
+        ip-protocol-list.h
         spawn-ask-password-agent.c
         spawn-ask-password-agent.h
         spawn-polkit-agent.c
@@ -137,6 +140,8 @@ shared_sources = files('''
         switch-root.h
         sysctl-util.c
         sysctl-util.h
+        tmpfile-util-label.c
+        tmpfile-util-label.h
         tomoyo-util.c
         tomoyo-util.h
         udev-util.c
@@ -186,44 +191,45 @@ if conf.get('HAVE_KMOD') == 1
         shared_sources += files('module-util.c')
 endif
 
-generate_socket_protocol_list = find_program('generate-socket-protocol-list.sh')
-socket_protocol_list_txt = custom_target(
-        'socket-protocol-list.txt',
-        output : 'socket-protocol-list.txt',
-        command : [generate_socket_protocol_list, cpp],
+generate_ip_protocol_list = find_program('generate-ip-protocol-list.sh')
+ip_protocol_list_txt = custom_target(
+        'ip-protocol-list.txt',
+        output : 'ip-protocol-list.txt',
+        command : [generate_ip_protocol_list, cpp],
         capture : true)
 
-fname = 'socket-protocol-from-name.gperf'
+fname = 'ip-protocol-from-name.gperf'
 gperf_file = custom_target(
         fname,
-        input : socket_protocol_list_txt,
+        input : ip_protocol_list_txt,
         output : fname,
-        command : [generate_gperfs, 'socket_protocol', 'IPPROTO_', '@INPUT@'],
+        command : [generate_gperfs, 'ip_protocol', 'IPPROTO_', '@INPUT@'],
         capture : true)
 
-fname = 'socket-protocol-from-name.h'
+fname = 'ip-protocol-from-name.h'
 target1 = custom_target(
         fname,
         input : gperf_file,
         output : fname,
         command : [gperf,
                    '-L', 'ANSI-C', '-t', '--ignore-case',
-                   '-N', 'lookup_socket_protocol',
-                   '-H', 'hash_socket_protocol_name',
+                   '-N', 'lookup_ip_protocol',
+                   '-H', 'hash_ip_protocol_name',
                    '-p', '-C',
                    '@INPUT@'],
         capture : true)
 
-fname = 'socket-protocol-to-name.h'
-awkscript = 'socket-protocol-to-name.awk'
+fname = 'ip-protocol-to-name.h'
+awkscript = 'ip-protocol-to-name.awk'
 target2 = custom_target(
         fname,
-        input : [awkscript, socket_protocol_list_txt],
+        input : [awkscript, ip_protocol_list_txt],
         output : fname,
         command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
         capture : true)
 
-shared_sources += [target1, target2]
+shared_generated_gperf_headers = [target1, target2]
+shared_sources += shared_generated_gperf_headers
 
 libshared_name = 'systemd-shared-@0@'.format(meson.project_version())
 
@@ -235,6 +241,7 @@ libshared_deps = [threads,
                   libgcrypt,
                   libiptc,
                   libkmod,
+                  libmount,
                   libseccomp,
                   libselinux,
                   libidn,
similarity index 58%
rename from src/basic/mount-util.c
rename to src/shared/mount-util.c
index ec607c7360a03e698d04f8334b0b5b4864f73ad1..9fa995f69355746bd0babeefca89992eac2c0880 100644 (file)
@@ -20,6 +20,7 @@
 #include "fs-util.h"
 #include "hashmap.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "string-util.h"
 #include "strv.h"
 
-/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
- * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
- * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
- * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
- * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
- * with large file handles anyway. */
-#define ORIGINAL_MAX_HANDLE_SZ 128
-
-int name_to_handle_at_loop(
-                int fd,
-                const char *path,
-                struct file_handle **ret_handle,
-                int *ret_mnt_id,
-                int flags) {
-
-        _cleanup_free_ struct file_handle *h = NULL;
-        size_t n = ORIGINAL_MAX_HANDLE_SZ;
-
-        /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
-         * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
-         * start value, it is not an upper bound on the buffer size required.
-         *
-         * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed
-         * as NULL if there's no interest in either. */
-
-        for (;;) {
-                int mnt_id = -1;
-
-                h = malloc0(offsetof(struct file_handle, f_handle) + n);
-                if (!h)
-                        return -ENOMEM;
-
-                h->handle_bytes = n;
-
-                if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) {
-
-                        if (ret_handle)
-                                *ret_handle = TAKE_PTR(h);
-
-                        if (ret_mnt_id)
-                                *ret_mnt_id = mnt_id;
-
-                        return 0;
-                }
-                if (errno != EOVERFLOW)
-                        return -errno;
-
-                if (!ret_handle && ret_mnt_id && mnt_id >= 0) {
-
-                        /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the
-                         * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to
-                         * be filled in, and the caller was interested in only the mount ID an nothing else. */
-
-                        *ret_mnt_id = mnt_id;
-                        return 0;
-                }
-
-                /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something
-                 * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small
-                 * buffer. In that case propagate EOVERFLOW */
-                if (h->handle_bytes <= n)
-                        return -EOVERFLOW;
-
-                /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */
-                n = h->handle_bytes;
-                if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */
-                        return -EOVERFLOW;
-
-                h = mfree(h);
-        }
-}
-
-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
-        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
-        _cleanup_free_ char *fdinfo = NULL;
-        _cleanup_close_ int subfd = -1;
-        char *p;
-        int r;
-
-        if ((flags & AT_EMPTY_PATH) && isempty(filename))
-                xsprintf(path, "/proc/self/fdinfo/%i", fd);
-        else {
-                subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
-                if (subfd < 0)
-                        return -errno;
-
-                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
-        }
-
-        r = read_full_file(path, &fdinfo, NULL);
-        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
-                return -EOPNOTSUPP;
-        if (r < 0)
-                return r;
-
-        p = startswith(fdinfo, "mnt_id:");
-        if (!p) {
-                p = strstr(fdinfo, "\nmnt_id:");
-                if (!p) /* The mnt_id field is a relatively new addition */
-                        return -EOPNOTSUPP;
-
-                p += 8;
-        }
-
-        p += strspn(p, WHITESPACE);
-        p[strcspn(p, WHITESPACE)] = 0;
-
-        return safe_atoi(p, mnt_id);
-}
-
-int fd_is_mount_point(int fd, const char *filename, int flags) {
-        _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
-        int mount_id = -1, mount_id_parent = -1;
-        bool nosupp = false, check_st_dev = true;
-        struct stat a, b;
-        int r;
-
-        assert(fd >= 0);
-        assert(filename);
-
-        /* First we will try the name_to_handle_at() syscall, which
-         * tells us the mount id and an opaque file "handle". It is
-         * not supported everywhere though (kernel compile-time
-         * option, not all file systems are hooked up). If it works
-         * the mount id is usually good enough to tell us whether
-         * something is a mount point.
-         *
-         * If that didn't work we will try to read the mount id from
-         * /proc/self/fdinfo/<fd>. This is almost as good as
-         * name_to_handle_at(), however, does not return the
-         * opaque file handle. The opaque file handle is pretty useful
-         * to detect the root directory, which we should always
-         * consider a mount point. Hence we use this only as
-         * fallback. Exporting the mnt_id in fdinfo is a pretty recent
-         * kernel addition.
-         *
-         * As last fallback we do traditional fstat() based st_dev
-         * comparisons. This is how things were traditionally done,
-         * but unionfs breaks this since it exposes file
-         * systems with a variety of st_dev reported. Also, btrfs
-         * subvolumes have different st_dev, even though they aren't
-         * real mounts of their own. */
-
-        r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
-        if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
-                /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked
-                 * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount
-                 * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness
-                 * (EINVAL): fall back to simpler logic. */
-                goto fallback_fdinfo;
-        else if (r == -EOPNOTSUPP)
-                /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs
-                 * supports it (in which case it is a mount point), otherwise fallback to the traditional stat()
-                 * logic */
-                nosupp = true;
-        else if (r < 0)
-                return r;
-
-        r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
-        if (r == -EOPNOTSUPP) {
-                if (nosupp)
-                        /* Neither parent nor child do name_to_handle_at()?  We have no choice but to fall back. */
-                        goto fallback_fdinfo;
-                else
-                        /* The parent can't do name_to_handle_at() but the directory we are interested in can?  If so,
-                         * it must be a mount point. */
-                        return 1;
-        } else if (r < 0)
-                return r;
-
-        /* The parent can do name_to_handle_at() but the
-         * directory we are interested in can't? If so, it
-         * must be a mount point. */
-        if (nosupp)
-                return 1;
-
-        /* If the file handle for the directory we are
-         * interested in and its parent are identical, we
-         * assume this is the root directory, which is a mount
-         * point. */
-
-        if (h->handle_bytes == h_parent->handle_bytes &&
-            h->handle_type == h_parent->handle_type &&
-            memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0)
-                return 1;
-
-        return mount_id != mount_id_parent;
-
-fallback_fdinfo:
-        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
-        if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM))
-                goto fallback_fstat;
-        if (r < 0)
-                return r;
-
-        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
-        if (r < 0)
-                return r;
-
-        if (mount_id != mount_id_parent)
-                return 1;
-
-        /* Hmm, so, the mount ids are the same. This leaves one
-         * special case though for the root file system. For that,
-         * let's see if the parent directory has the same inode as we
-         * are interested in. Hence, let's also do fstat() checks now,
-         * too, but avoid the st_dev comparisons, since they aren't
-         * that useful on unionfs mounts. */
-        check_st_dev = false;
-
-fallback_fstat:
-        /* yay for fstatat() taking a different set of flags than the other
-         * _at() above */
-        if (flags & AT_SYMLINK_FOLLOW)
-                flags &= ~AT_SYMLINK_FOLLOW;
-        else
-                flags |= AT_SYMLINK_NOFOLLOW;
-        if (fstatat(fd, filename, &a, flags) < 0)
-                return -errno;
-
-        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
-                return -errno;
-
-        /* A directory with same device and inode as its parent? Must
-         * be the root directory */
-        if (a.st_dev == b.st_dev &&
-            a.st_ino == b.st_ino)
-                return 1;
-
-        return check_st_dev && (a.st_dev != b.st_dev);
-}
-
-/* flags can be AT_SYMLINK_FOLLOW or 0 */
-int path_is_mount_point(const char *t, const char *root, int flags) {
-        _cleanup_free_ char *canonical = NULL;
-        _cleanup_close_ int fd = -1;
-        int r;
-
-        assert(t);
-        assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
-
-        if (path_equal(t, "/"))
-                return 1;
-
-        /* we need to resolve symlinks manually, we can't just rely on
-         * fd_is_mount_point() to do that for us; if we have a structure like
-         * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
-         * look at needs to be /usr, not /. */
-        if (flags & AT_SYMLINK_FOLLOW) {
-                r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical);
-                if (r < 0)
-                        return r;
-
-                t = canonical;
-        }
-
-        fd = open_parent(t, O_PATH|O_CLOEXEC, 0);
-        if (fd < 0)
-                return -errno;
-
-        return fd_is_mount_point(fd, last_path_component(t), flags);
-}
-
-int path_get_mnt_id(const char *path, int *ret) {
-        int r;
-
-        r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
-        if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
-                return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
-
-        return r;
-}
-
 int umount_recursive(const char *prefix, int flags) {
         bool again;
         int n = 0, r;
@@ -601,86 +329,6 @@ int mount_move_root(const char *path) {
         return 0;
 }
 
-bool fstype_is_network(const char *fstype) {
-        const char *x;
-
-        x = startswith(fstype, "fuse.");
-        if (x)
-                fstype = x;
-
-        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");
-}
-
-bool fstype_can_uid_gid(const char *fstype) {
-
-        /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
-         * current and future. */
-
-        return STR_IN_SET(fstype,
-                          "adfs",
-                          "fat",
-                          "hfs",
-                          "hpfs",
-                          "iso9660",
-                          "msdos",
-                          "ntfs",
-                          "vfat");
-}
-
 int repeat_unmount(const char *path, int flags) {
         bool done = false;
 
@@ -852,37 +500,6 @@ int umount_verbose(const char *what) {
         return 0;
 }
 
-const char *mount_propagation_flags_to_string(unsigned long flags) {
-
-        switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) {
-        case 0:
-                return "";
-        case MS_SHARED:
-                return "shared";
-        case MS_SLAVE:
-                return "slave";
-        case MS_PRIVATE:
-                return "private";
-        }
-
-        return NULL;
-}
-
-int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
-
-        if (isempty(name))
-                *ret = 0;
-        else if (streq(name, "shared"))
-                *ret = MS_SHARED;
-        else if (streq(name, "slave"))
-                *ret = MS_SLAVE;
-        else if (streq(name, "private"))
-                *ret = MS_PRIVATE;
-        else
-                return -EINVAL;
-        return 0;
-}
-
 int mount_option_mangle(
                 const char *options,
                 unsigned long mount_flags,
@@ -951,46 +568,3 @@ int mount_option_mangle(
 
         return 0;
 }
-
-int dev_is_devtmpfs(void) {
-        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-        int mount_id, r;
-        char *e;
-
-        r = path_get_mnt_id("/dev", &mount_id);
-        if (r < 0)
-                return r;
-
-        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
-        if (!proc_self_mountinfo)
-                return -errno;
-
-        (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                int mid;
-
-                r = read_line(proc_self_mountinfo, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (sscanf(line, "%i", &mid) != 1)
-                        continue;
-
-                if (mid != mount_id)
-                        continue;
-
-                e = strstr(line, " - ");
-                if (!e)
-                        continue;
-
-                /* accept any name that starts with the currently expected type */
-                if (startswith(e + 3, "devtmpfs"))
-                        return true;
-        }
-
-        return false;
-}
similarity index 57%
rename from src/basic/mount-util.h
rename to src/shared/mount-util.h
index ad8c47cb325f89b97ecbc3b08dbe31b557d2754b..00df1b0e55e656742842c218c0ca5c43ae393da9 100644 (file)
@@ -1,25 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <fcntl.h>
 #include <mntent.h>
-#include <stdbool.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
 
 #include "macro.h"
-#include "missing.h"
-
-int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags);
-
-int path_get_mnt_id(const char *path, int *ret);
-
-int fd_is_mount_point(int fd, const char *filename, int flags);
-int path_is_mount_point(const char *path, const char *root, int flags);
 
 int repeat_unmount(const char *path, int flags);
-
 int umount_recursive(const char *target, int flags);
 int bind_remount_recursive(const char *prefix, bool ro, char **blacklist);
 int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo);
@@ -29,14 +16,6 @@ int mount_move_root(const char *path);
 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);
-bool fstype_can_uid_gid(const char *fstype);
-
-const char* mode_to_inaccessible_node(mode_t mode);
-
 int mount_verbose(
                 int error_log_level,
                 const char *what,
@@ -46,13 +25,10 @@ int mount_verbose(
                 const char *options);
 int umount_verbose(const char *where);
 
-const char *mount_propagation_flags_to_string(unsigned long flags);
-int mount_propagation_flags_from_string(const char *name, unsigned long *ret);
-
 int mount_option_mangle(
                 const char *options,
                 unsigned long mount_flags,
                 unsigned long *ret_mount_flags,
                 char **ret_remaining_options);
 
-int dev_is_devtmpfs(void);
+const char* mode_to_inaccessible_node(mode_t mode);
index a5beb9200fafbcaeaa01c0a3d798c6cdd0543737..8cc2d0873db2da20252a4f37d0f00c1024512792 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <sched.h>
+#include <errno.h>
 
 #include "alloc-util.h"
 #include "extract-word.h"
index 7cc26a441d4bb44558321cebfc73dac14ae70da5..0aeb0bc89143921538323d86eb12bf74efc718e6 100644 (file)
@@ -1,9 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <sched.h>
-
-#include "missing.h"
+#include "missing_sched.h"
 
 /* The combination of all namespace flags defined by the kernel. The right type for this isn't clear. setns() and
  * unshare() expect these flags to be passed as (signed) "int", while clone() wants them as "unsigned long". The latter
index 82471a45ba0541e5315e91b190010c72c60346bf..f7d46d3c477969e61af4a35a070e67b858cb9cfb 100644 (file)
@@ -1,13 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "os-util.h"
-#include "strv.h"
-#include "fileio.h"
 #include "string-util.h"
+#include "strv.h"
 
 int path_is_os_tree(const char *path) {
         int r;
index 9463d185f0efe25bc432b8e95c22354935493b36..107b345538cf7e230f63427f9eec9a7d4ad4239f 100644 (file)
@@ -3,6 +3,24 @@
 #include "output-mode.h"
 #include "string-table.h"
 
+JsonFormatFlags output_mode_to_json_format_flags(OutputMode m) {
+
+        switch (m) {
+
+        case OUTPUT_JSON_SSE:
+                return JSON_FORMAT_SSE;
+
+        case OUTPUT_JSON_SEQ:
+                return JSON_FORMAT_SEQ;
+
+        case OUTPUT_JSON_PRETTY:
+                return JSON_FORMAT_PRETTY;
+
+        default:
+                return JSON_FORMAT_NEWLINE;
+        }
+}
+
 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
         [OUTPUT_SHORT] = "short",
         [OUTPUT_SHORT_FULL] = "short-full",
index 3cbaeadde6877bf198acbfb57c9fc3eabeb94efb..00b603205671902e5c93ec95b65f82ab1727898f 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "json.h"
 #include "macro.h"
 
 typedef enum OutputMode {
@@ -23,6 +24,10 @@ typedef enum OutputMode {
         _OUTPUT_MODE_INVALID = -1
 } OutputMode;
 
+static inline bool OUTPUT_MODE_IS_JSON(OutputMode m) {
+        return IN_SET(m, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ);
+}
+
 /* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the
  * logs output, others only to the process tree output. */
 
@@ -39,5 +44,7 @@ typedef enum OutputFlags {
         OUTPUT_NO_HOSTNAME    = 1 << 9,
 } OutputFlags;
 
+JsonFormatFlags output_mode_to_json_format_flags(OutputMode m);
+
 const char* output_mode_to_string(OutputMode m) _const_;
 OutputMode output_mode_from_string(const char *s) _pure_;
index 88d9ef349e7ee00d213d35ed60204094ddea4afc..ce4ca9bdb25d63e01dca6312d77e7683a88b9ddb 100644 (file)
@@ -19,6 +19,7 @@
 #include "macro.h"
 #include "pager.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -55,7 +56,7 @@ static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) {
         file = fdopen(exe_name_fd, "r");
         if (!file) {
                 safe_close(exe_name_fd);
-                return log_debug_errno(errno, "Failed to create FILE object: %m");
+                return log_error_errno(errno, "Failed to create FILE object: %m");
         }
 
         /* Find the last line */
@@ -64,7 +65,7 @@ static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) {
 
                 r = read_line(file, LONG_LINE_MAX, &t);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to read from socket: %m");
                 if (r == 0)
                         break;
 
@@ -96,7 +97,7 @@ int pager_open(PagerFlags flags) {
                 return 0;
 
         if (!is_main_thread())
-                return -EPERM;
+                return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Pager invoked from wrong thread.");
 
         pager = getenv("SYSTEMD_PAGER");
         if (!pager)
@@ -105,7 +106,7 @@ int pager_open(PagerFlags flags) {
         if (pager) {
                 pager_args = strv_split(pager, WHITESPACE);
                 if (!pager_args)
-                        return -ENOMEM;
+                        return log_oom();
 
                 /* If the pager is explicitly turned off, honour it */
                 if (strv_isempty(pager_args) || strv_equal(pager_args, STRV_MAKE("cat")))
@@ -131,7 +132,7 @@ int pager_open(PagerFlags flags) {
         if (flags & PAGER_JUMP_TO_END)
                 less_opts = strjoina(less_opts, " +G");
 
-        r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pager_pid);
+        r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pager_pid);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -139,11 +140,17 @@ int pager_open(PagerFlags flags) {
 
                 /* In the child start the pager */
 
-                (void) dup2(fd[0], STDIN_FILENO);
+                if (dup2(fd[0], STDIN_FILENO) < 0) {
+                        log_error_errno(errno, "Failed to duplicate file descriptor to STDIN: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
                 safe_close_pair(fd);
 
-                if (setenv("LESS", less_opts, 1) < 0)
+                if (setenv("LESS", less_opts, 1) < 0) {
+                        log_error_errno(errno, "Failed to set environment variable LESS: %m");
                         _exit(EXIT_FAILURE);
+                }
 
                 /* Initialize a good charset for less. This is
                  * particularly important if we output UTF-8
@@ -152,14 +159,21 @@ int pager_open(PagerFlags flags) {
                 if (!less_charset && is_locale_utf8())
                         less_charset = "utf-8";
                 if (less_charset &&
-                    setenv("LESSCHARSET", less_charset, 1) < 0)
+                    setenv("LESSCHARSET", less_charset, 1) < 0) {
+                        log_error_errno(errno, "Failed to set environment variable LESSCHARSET: %m");
                         _exit(EXIT_FAILURE);
+                }
 
                 if (pager_args) {
-                        if (loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false) < 0)
+                        r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false);
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to write pager name to socket: %m");
                                 _exit(EXIT_FAILURE);
+                        }
 
                         execvp(pager_args[0], pager_args);
+                        log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+                                       "Failed execute %s, using fallback pagers: %m", pager_args[0]);
                 }
 
                 /* Debian's alternatives command for pagers is
@@ -169,13 +183,21 @@ int pager_open(PagerFlags flags) {
                  * is similar to this one anyway, but is
                  * Debian-specific. */
                 FOREACH_STRING(exe, "pager", "less", "more") {
-                        if (loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false) < 0)
+                        r = loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false);
+                        if (r  < 0) {
+                                log_error_errno(r, "Failed to write pager name to socket: %m");
                                 _exit(EXIT_FAILURE);
+                        }
                         execlp(exe, exe, NULL);
+                        log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+                                       "Failed execute %s, using next fallback pager: %m", exe);
                 }
 
-                if (loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in") + 1, false) < 0)
+                r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in") + 1, false);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to write pager name to socket: %m");
                         _exit(EXIT_FAILURE);
+                }
                 pager_fallback();
                 /* not reached */
         }
@@ -256,7 +278,7 @@ int show_man_page(const char *desc, bool null_stdio) {
         } else
                 args[1] = desc;
 
-        r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_LOG, &pid);
+        r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
index dc06502c8118e4ad744066bbed2b1a1d44544cef..442fde7b2d2db732158a0e0974c7183b091f3b34 100644 (file)
@@ -6,7 +6,6 @@
 #include <string.h>
 
 #include "alloc-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "install.h"
 #include "log.h"
@@ -18,6 +17,7 @@
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index 108601864550576d6b9ccca6b6f6cf7ff5cc9697..de6274a3dab91b568791811dce7ecd01ea2a343c 100644 (file)
@@ -60,10 +60,38 @@ int terminal_urlify(const char *url, const char *text, char **ret) {
         return 0;
 }
 
-int terminal_urlify_path(const char *path, const char *text, char **ret) {
+int file_url_from_path(const char *path, char **ret) {
         _cleanup_free_ char *absolute = NULL;
         struct utsname u;
-        const char *url;
+        char *url = NULL;
+        int r;
+
+        if (uname(&u) < 0)
+                return -errno;
+
+        if (!path_is_absolute(path)) {
+                r = path_make_absolute_cwd(path, &absolute);
+                if (r < 0)
+                        return r;
+
+                path = absolute;
+        }
+
+        /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local
+         * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested
+         * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly
+         * careful with validating the strings either. */
+
+        url = strjoin("file://", u.nodename, path);
+        if (!url)
+                return -ENOMEM;
+
+        *ret = url;
+        return 0;
+}
+
+int terminal_urlify_path(const char *path, const char *text, char **ret) {
+        _cleanup_free_ char *url = NULL;
         int r;
 
         assert(path);
@@ -88,23 +116,9 @@ int terminal_urlify_path(const char *path, const char *text, char **ret) {
                 return 0;
         }
 
-        if (uname(&u) < 0)
-                return -errno;
-
-        if (!path_is_absolute(path)) {
-                r = path_make_absolute_cwd(path, &absolute);
-                if (r < 0)
-                        return r;
-
-                path = absolute;
-        }
-
-        /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local
-         * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested
-         * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly
-         * careful with validating the strings either. */
-
-        url = strjoina("file://", u.nodename, path);
+        r = file_url_from_path(path, &url);
+        if (r < 0)
+                return r;
 
         return terminal_urlify(url, text, ret);
 }
index cf9a70dd9e6abd7128563aa9055a38f9bd8675db..12ab9acf58ba41fcb3a039d2fbc98d31ab2af590 100644 (file)
@@ -3,6 +3,8 @@
 
 void print_separator(void);
 
+int file_url_from_path(const char *path, char **ret);
+
 int terminal_urlify(const char *url, const char *text, char **ret);
 int terminal_urlify_path(const char *path, const char *text, char **ret);
 int terminal_urlify_man(const char *page, const char *section, char **ret);
index 1cb7ea3a197f9c251fb0e38724d3e605e721bdc2..fe17b3781aafc730a381d3dfbe1389a0bd9addf5 100644 (file)
@@ -392,11 +392,14 @@ int pty_forward_new(
         struct winsize ws;
         int r;
 
-        f = new0(PTYForward, 1);
+        f = new(PTYForward, 1);
         if (!f)
                 return -ENOMEM;
 
-        f->flags = flags;
+        *f = (struct PTYForward) {
+                .flags = flags,
+                .master = -1,
+        };
 
         if (event)
                 f->event = sd_event_ref(event);
@@ -587,3 +590,42 @@ int pty_forward_set_priority(PTYForward *f, int64_t priority) {
 
         return 0;
 }
+
+int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height) {
+        struct winsize ws;
+
+        assert(f);
+
+        if (width == (unsigned) -1 && height == (unsigned) -1)
+                return 0; /* noop */
+
+        if (width != (unsigned) -1 &&
+            (width == 0 || width > USHRT_MAX))
+                return -ERANGE;
+
+        if (height != (unsigned) -1 &&
+            (height == 0 || height > USHRT_MAX))
+                return -ERANGE;
+
+        if (width == (unsigned) -1 || height == (unsigned) -1) {
+                if (ioctl(f->master, TIOCGWINSZ, &ws) < 0)
+                        return -errno;
+
+                if (width != (unsigned) -1)
+                        ws.ws_col = width;
+                if (height != (unsigned) -1)
+                        ws.ws_row = height;
+        } else
+                ws = (struct winsize) {
+                        .ws_row = height,
+                        .ws_col = width,
+                };
+
+        if (ioctl(f->master, TIOCSWINSZ, &ws) < 0)
+                return -errno;
+
+        /* Make sure we ignore SIGWINCH window size events from now on */
+        f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
+
+        return 0;
+}
index e4a083ac2414944a23f3cfccb273f87f954b6c3f..887d3cba53a0b651429b8f04941203dae9e3dffd 100644 (file)
@@ -19,7 +19,7 @@ typedef enum PTYForwardFlags {
         PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4,
 } PTYForwardFlags;
 
-typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void*userdata);
+typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void *userdata);
 
 int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f);
 PTYForward *pty_forward_free(PTYForward *f);
@@ -37,4 +37,6 @@ bool pty_forward_drain(PTYForward *f);
 
 int pty_forward_set_priority(PTYForward *f, int64_t priority);
 
+int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height);
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
index 67ccd43c3f01a0093fc40a43dca588139f7234e6..42d6dd2a94342ba4d7f7cb17e568cea2bda39f85 100644 (file)
@@ -371,8 +371,6 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 .value =
                 "lookup_dcookie\0"
                 "perf_event_open\0"
-                "process_vm_readv\0"
-                "process_vm_writev\0"
                 "ptrace\0"
                 "rtas\0"
 #ifdef __NR_s390_runtime_instr
index ad091f6d9530ad20fb051b4bf6e78d10a91d6f30..6d31dfeff0a28e55522d281d6cb3c53b00f65f28 100644 (file)
@@ -5,7 +5,6 @@
 
 #include "alloc-util.h"
 #include "extract-word.h"
-#include "securebits.h"
 #include "securebits-util.h"
 #include "string-util.h"
 
index 3cb3cb3d0857b23d2d0dbc4d72e612bdb20756a2..b5ec6ee0e683e54af59fd777800bd8acb3cd38c3 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "securebits.h"
+#include "missing_securebits.h"
 
 int secure_bits_to_string_alloc(int i, char **s);
 int secure_bits_from_string(const char *s);
index eb1191b3bfa1227654286459d2616222248507e1..0333f87b7b21b8bab4073f6c72c2f22351732585 100644 (file)
@@ -1,12 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/mman.h>
+
 #include "alloc-util.h"
 #include "env-util.h"
 #include "escape.h"
 #include "fileio.h"
+#include "missing.h"
 #include "parse-util.h"
+#include "process-util.h"
 #include "serialize.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 
 int serialize_item(FILE *f, const char *key, const char *value) {
         assert(f);
@@ -188,3 +193,22 @@ int deserialize_environment(const char *value, char ***list) {
         unescaped = NULL; /* now part of 'list' */
         return 0;
 }
+
+int open_serialization_fd(const char *ident) {
+        int fd;
+
+        fd = memfd_create(ident, MFD_CLOEXEC);
+        if (fd < 0) {
+                const char *path;
+
+                path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
+                fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
+                if (fd < 0)
+                        return fd;
+
+                log_debug("Serializing %s to %s.", ident, path);
+        } else
+                log_debug("Serializing %s to memfd.", ident);
+
+        return fd;
+}
index a671524153b705994ddc15279424d2ffdec7670f..4cbd98bb34489a3c02bec798f7d18af86d4b6e24 100644 (file)
@@ -21,3 +21,5 @@ static inline int serialize_bool(FILE *f, const char *key, bool b) {
 int deserialize_usec(const char *value, usec_t *timestamp);
 int deserialize_dual_timestamp(const char *value, dual_timestamp *t);
 int deserialize_environment(const char *value, char ***environment);
+
+int open_serialization_fd(const char *ident);
index 9ea88a37b449a954c1373624eb2423bb59c32174..1c94714f8ac0a7f4d3e94acc726bd552a93b9b68 100644 (file)
@@ -9,6 +9,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/utsname.h>
 #include <syslog.h>
 #include <unistd.h>
diff --git a/src/shared/socket-protocol-list.c b/src/shared/socket-protocol-list.c
deleted file mode 100644 (file)
index 797f1e9..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <string.h>
-
-#include "socket-protocol-list.h"
-#include "macro.h"
-
-static const struct socket_protocol_name* lookup_socket_protocol(register const char *str, register GPERF_LEN_TYPE len);
-
-#include "socket-protocol-from-name.h"
-#include "socket-protocol-to-name.h"
-
-const char *socket_protocol_to_name(int id) {
-
-        if (id < 0)
-                return NULL;
-
-        if (id >= (int) ELEMENTSOF(socket_protocol_names))
-                return NULL;
-
-        return socket_protocol_names[id];
-}
-
-int socket_protocol_from_name(const char *name) {
-        const struct socket_protocol_name *sc;
-
-        assert(name);
-
-        sc = lookup_socket_protocol(name, strlen(name));
-        if (!sc)
-                return -EINVAL;
-
-        return sc->id;
-}
-
-int socket_protocol_max(void) {
-        return ELEMENTSOF(socket_protocol_names);
-}
diff --git a/src/shared/socket-protocol-list.h b/src/shared/socket-protocol-list.h
deleted file mode 100644 (file)
index 458904d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-#pragma once
-
-const char *socket_protocol_to_name(int id);
-int socket_protocol_from_name(const char *name);
-
-int socket_protocol_max(void);
index c0dfa4bc4862b3ae94eeb715978c0fd1b7e1c85e..ee31c448fc80b3fee8548254e09b0927a684b870 100644 (file)
@@ -16,6 +16,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stdio-util.h"
index bab39685ff60141c4cff855d2423f134d52f8eba..11ea12ed69745665219bde8da8a6ace4f707dc89 100644 (file)
@@ -14,8 +14,8 @@
 #undef basename
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "env-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "log.h"
 #include "path-util.h"
@@ -46,7 +46,7 @@ static void load_testdata_env(void) {
         assert_se(readlink_and_make_absolute("/proc/self/exe", &s) >= 0);
         dirname(s);
 
-        envpath = path_join(NULL, s, "systemd-runtest.env");
+        envpath = path_join(s, "systemd-runtest.env");
         if (load_env_file_pairs(NULL, envpath, &pairs) < 0)
                 return;
 
diff --git a/src/shared/tmpfile-util-label.c b/src/shared/tmpfile-util-label.c
new file mode 100644 (file)
index 0000000..c12d7c1
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/stat.h>
+
+#include "selinux-util.h"
+#include "tmpfile-util-label.h"
+#include "tmpfile-util.h"
+
+int fopen_temporary_label(
+                const char *target,
+                const char *path,
+                FILE **f,
+                char **temp_path) {
+
+        int r;
+
+        r = mac_selinux_create_file_prepare(target, S_IFREG);
+        if (r < 0)
+                return r;
+
+        r = fopen_temporary(path, f, temp_path);
+
+        mac_selinux_create_file_clear();
+
+        return r;
+}
diff --git a/src/shared/tmpfile-util-label.h b/src/shared/tmpfile-util-label.h
new file mode 100644 (file)
index 0000000..97a8751
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdio.h>
+
+/* These functions are split out of tmpfile-util.h (and not for example just flags to the functions they wrap) in order
+ * to optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux, but
+ * not for all */
+
+int fopen_temporary_label(const char *target, const char *path, FILE **f, char **temp_path);
index 87ff6d288f45746523a24f36e7c9f88f3d4f46b1..fdeaf8f613e5c2138ae3cd3e2259923ab8fedcde 100644 (file)
@@ -4,7 +4,7 @@
 #include <string.h>
 
 #include "alloc-util.h"
-#include "fileio.h"
+#include "env-file.h"
 #include "log.h"
 #include "parse-util.h"
 #include "string-table.h"
index e174255a76d6544baaa2481052f27a9fbbfd3750..010c0df3fdc97f7d05bc9d9f8030e8cd34319be7 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdbool.h>
+
 #define VERB_ANY ((unsigned) -1)
 
 typedef enum VerbFlags {
index 82481972f08dd8269c00c30c21a8b6f36f4d65e6..6d65efbb9ea55ab691f1566bca06ba43ca48a5fe 100644 (file)
@@ -69,7 +69,7 @@ static int fork_wait(const char* const cmdline[]) {
         pid_t pid;
         int r;
 
-        r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+        r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
index 38545e8f5ebdd017166381689908bd8438276944..40fcb2cae3ef962b3970516385972dc050af5206 100644 (file)
@@ -1,7 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  Copyright © 2013 Marc-Antoine Perennou
-***/
 
 #include <errno.h>
 #include <fcntl.h>
@@ -37,7 +34,6 @@
 #include "escape.h"
 #include "exit-status.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "glob-util.h"
@@ -73,6 +69,7 @@
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tmpfile-util.h"
 #include "unit-def.h"
 #include "unit-name.h"
 #include "user-util.h"
@@ -2415,7 +2412,7 @@ static void warn_unit_file_changed(const char *name) {
                     arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
 }
 
-static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
+static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
         char **p;
 
         assert(lp);
@@ -2425,7 +2422,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
                 _cleanup_free_ char *path = NULL, *lpath = NULL;
                 int r;
 
-                path = path_join(NULL, *p, unit_name);
+                path = path_join(*p, unit_name);
                 if (!path)
                         return log_oom();
 
@@ -2437,42 +2434,58 @@ 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);
 
-                if (unit_path)
-                        *unit_path = TAKE_PTR(lpath);
+                if (ret_unit_path)
+                        *ret_unit_path = TAKE_PTR(lpath);
 
                 return 1;
         }
 
+        if (ret_unit_path)
+                *ret_unit_path = NULL;
+
         return 0;
 }
 
 static int unit_find_template_path(
                 const char *unit_name,
                 LookupPaths *lp,
-                char **fragment_path,
-                char **template) {
+                char **ret_fragment_path,
+                char **ret_template) {
 
-        _cleanup_free_ char *_template = NULL;
+        _cleanup_free_ char *t = NULL, *f = 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_file_find_path(lp, unit_name, &f);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                if (ret_fragment_path)
+                        *ret_fragment_path = TAKE_PTR(f);
+                if (ret_template)
+                        *ret_template = NULL;
+                return r; /* found a real unit */
+        }
+
+        r = unit_name_template(unit_name, &t);
+        if (r == -EINVAL) {
+                if (ret_fragment_path)
+                        *ret_fragment_path = NULL;
+                if (ret_template)
+                        *ret_template = NULL;
 
-        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);
+        r = unit_file_find_path(lp, t, ret_fragment_path);
         if (r < 0)
                 return r;
 
-        if (template)
-                *template = TAKE_PTR(_template);
+        if (ret_template)
+                *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
 
         return r;
 }
@@ -2481,33 +2494,59 @@ static int unit_find_paths(
                 sd_bus *bus,
                 const char *unit_name,
                 LookupPaths *lp,
-                char **fragment_path,
-                char ***dropin_paths) {
+                bool force_client_side,
+                char **ret_fragment_path,
+                char ***ret_dropin_paths) {
 
-        _cleanup_free_ char *path = NULL;
         _cleanup_strv_free_ char **dropins = NULL;
+        _cleanup_free_ char *path = NULL;
         int r;
 
         /**
-         * Finds where the unit is defined on disk. Returns 0 if the unit
-         * is not found. Returns 1 if it is found, and sets
-         * - the path to the unit in *path, if it exists on disk,
-         * - and a strv of existing drop-ins in *dropins,
-         *   if the arg is not NULL and any dropins were found.
+         * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is found, and
+         * sets:
+         * - the path to the unit in *ret_frament_path, if it exists on disk,
+         * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins were found.
+         *
+         * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for some
+         * reason (the latter only applies if we are going through the service manager)
          */
 
         assert(unit_name);
-        assert(fragment_path);
+        assert(ret_fragment_path);
         assert(lp);
 
-        if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+        /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
+        if (!force_client_side &&
+            !install_client_side() &&
+            !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_free_ char *unit = NULL;
+                _cleanup_free_ char *load_state = NULL, *unit = NULL;
 
                 unit = unit_dbus_path_from_name(unit_name);
                 if (!unit)
                         return log_oom();
 
+                r = sd_bus_get_property_string(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                unit,
+                                "org.freedesktop.systemd1.Unit",
+                                "LoadState",
+                                &error,
+                                &load_state);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get LoadState: %s", bus_error_message(&error, r));
+
+                if (streq(load_state, "masked"))
+                        return -ERFKILL;
+                if (streq(load_state, "not-found")) {
+                        r = 0;
+                        goto not_found;
+                }
+                if (!streq(load_state, "loaded"))
+                        return -EKEYREJECTED;
+
                 r = sd_bus_get_property_string(
                                 bus,
                                 "org.freedesktop.systemd1",
@@ -2519,7 +2558,7 @@ static int unit_find_paths(
                 if (r < 0)
                         return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
 
-                if (dropin_paths) {
+                if (ret_dropin_paths) {
                         r = sd_bus_get_property_strv(
                                         bus,
                                         "org.freedesktop.systemd1",
@@ -2542,7 +2581,6 @@ static int unit_find_paths(
                 r = unit_find_template_path(unit_name, lp, &path, &template);
                 if (r < 0)
                         return r;
-
                 if (r > 0) {
                         if (null_or_empty_path(path))
                                 /* The template is masked. Let's cut the process short. */
@@ -2566,25 +2604,29 @@ static int unit_find_paths(
                 if (r < 0)
                         return log_error_errno(r, "Failed to add unit name: %m");
 
-                if (dropin_paths) {
-                        r = unit_file_find_dropin_conf_paths(arg_root, lp->search_path,
-                                                             NULL, names, &dropins);
+                if (ret_dropin_paths) {
+                        r = unit_file_find_dropin_conf_paths(arg_root, lp->search_path, NULL, names, &dropins);
                         if (r < 0)
                                 return r;
                 }
         }
 
-        r = 0;
+                r = 0;
 
         if (!isempty(path)) {
-                *fragment_path = TAKE_PTR(path);
+                *ret_fragment_path = TAKE_PTR(path);
                 r = 1;
-        }
+        } else
+                *ret_fragment_path = NULL;
 
-        if (dropin_paths && !strv_isempty(dropins)) {
-                *dropin_paths = TAKE_PTR(dropins);
-                r = 1;
+        if (ret_dropin_paths) {
+                if (!strv_isempty(dropins)) {
+                        *ret_dropin_paths = TAKE_PTR(dropins);
+                        r = 1;
+                } else
+                        *ret_dropin_paths = NULL;
         }
+
  not_found:
         if (r == 0 && !arg_force)
                 log_error("No files found for %s.", unit_name);
@@ -2757,63 +2799,87 @@ static void wait_context_free(WaitContext *c) {
 }
 
 static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        const char *path, *interface, *active_state = NULL, *job_path = NULL;
         WaitContext *c = userdata;
-        const char *path;
+        bool is_failed;
         int r;
 
+        /* Called whenever we get a PropertiesChanged signal. Checks if ActiveState changed to inactive/failed.
+         *
+         * Signal parameters: (s interface, a{sv} changed_properties, as invalidated_properties) */
+
         path = sd_bus_message_get_path(m);
         if (!set_contains(c->unit_paths, path))
                 return 0;
 
-        /* Check if ActiveState changed to inactive/failed */
-        /* (s interface, a{sv} changed_properties, as invalidated_properties) */
-        r = sd_bus_message_skip(m, "s");
+        r = sd_bus_message_read(m, "s", &interface);
         if (r < 0)
                 return bus_log_parse_error(r);
 
+        if (!streq(interface, "org.freedesktop.systemd1.Unit")) /* ActiveState is on the Unit interface */
+                return 0;
+
         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+        for (;;) {
                 const char *s;
 
-                r = sd_bus_message_read(m, "s", &s);
+                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
+                if (r < 0)
+                        return bus_log_parse_error(r);
+                if (r == 0) /* end of array */
+                        break;
+
+                r = sd_bus_message_read(m, "s", &s); /* Property name */
                 if (r < 0)
                         return bus_log_parse_error(r);
 
                 if (streq(s, "ActiveState")) {
-                        bool is_failed;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s");
+                        r = sd_bus_message_read(m, "v", "s", &active_state);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        r = sd_bus_message_read(m, "s", &s);
+                        if (job_path) /* Found everything we need */
+                                break;
+
+                } else if (streq(s, "Job")) {
+                        uint32_t job_id;
+
+                        r = sd_bus_message_read(m, "v", "(uo)", &job_id, &job_path);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        is_failed = streq(s, "failed");
-                        if (streq(s, "inactive") || is_failed) {
-                                log_debug("%s became %s, dropping from --wait tracking", path, s);
-                                free(set_remove(c->unit_paths, path));
-                                c->any_failed = c->any_failed || is_failed;
-                        } else
-                                log_debug("ActiveState on %s changed to %s", path, s);
+                        /* There's still a job pending for this unit, let's ignore this for now, and return right-away. */
+                        if (job_id != 0)
+                                return 0;
+
+                        if (active_state) /* Found everything we need */
+                                break;
 
-                        break; /* no need to dissect the rest of the message */
                 } else {
-                        /* other property */
-                        r = sd_bus_message_skip(m, "v");
+                        r = sd_bus_message_skip(m, "v"); /* Other property */
                         if (r < 0)
                                 return bus_log_parse_error(r);
                 }
+
                 r = sd_bus_message_exit_container(m);
                 if (r < 0)
                         return bus_log_parse_error(r);
         }
-        if (r < 0)
-                return bus_log_parse_error(r);
+
+        /* If this didn't contain the ActiveState property we can't do anything */
+        if (!active_state)
+                return 0;
+
+        is_failed = streq(active_state, "failed");
+        if (streq(active_state, "inactive") || is_failed) {
+                log_debug("%s became %s, dropping from --wait tracking", path, active_state);
+                free(set_remove(c->unit_paths, path));
+                c->any_failed = c->any_failed || is_failed;
+        } else
+                log_debug("ActiveState on %s changed to %s", path, active_state);
 
         if (set_isempty(c->unit_paths))
                 sd_event_exit(c->event, EXIT_SUCCESS);
@@ -3024,6 +3090,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
         _cleanup_(wait_context_free) WaitContext wait_context = {};
         const char *method, *mode, *one_name, *suffix = NULL;
+        _cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
         _cleanup_strv_free_ char **names = NULL;
         int r, ret = EXIT_SUCCESS;
         sd_bus *bus;
@@ -3120,6 +3187,12 @@ static int start_unit(int argc, char *argv[], void *userdata) {
                 r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
                 if (ret == EXIT_SUCCESS && r < 0)
                         ret = translate_bus_error_to_exit_status(r, &error);
+
+                if (r >= 0 && streq(method, "StopUnit")) {
+                        r = strv_push(&stopped_units, *name);
+                        if (r < 0)
+                                return log_oom();
+                }
         }
 
         if (!arg_no_block) {
@@ -3144,8 +3217,8 @@ static int start_unit(int argc, char *argv[], void *userdata) {
 
                 /* When stopping units, warn if they can still be triggered by
                  * another active unit (socket, path, timer) */
-                if (!arg_quiet && streq(method, "StopUnit"))
-                        STRV_FOREACH(name, names)
+                if (!arg_quiet)
+                        STRV_FOREACH(name, stopped_units)
                                 (void) check_triggering_units(bus, *name);
         }
 
@@ -3471,9 +3544,9 @@ static int load_kexec_kernel(void) {
                 return -EINVAL;
         }
 
-        kernel = path_join(NULL, where, e->kernel);
+        kernel = path_join(where, e->kernel);
         if (!strv_isempty(e->initrd))
-                initrd = path_join(NULL, where, *e->initrd);
+                initrd = path_join(where, *e->initrd);
         options = strv_join(e->options, " ");
         if (!options)
                 return log_oom();
@@ -3487,7 +3560,7 @@ static int load_kexec_kernel(void) {
         if (arg_dry_run)
                 return 0;
 
-        r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+        r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -5374,9 +5447,16 @@ static int cat(int argc, char *argv[], void *userdata) {
                 _cleanup_free_ char *fragment_path = NULL;
                 _cleanup_strv_free_ char **dropin_paths = NULL;
 
-                r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
+                r = unit_find_paths(bus, *name, &lp, false, &fragment_path, &dropin_paths);
                 if (r == -ERFKILL) {
-                        printf("%s# unit %s is masked%s\n",
+                        printf("%s# Unit %s is masked%s.\n",
+                               ansi_highlight_magenta(),
+                               *name,
+                               ansi_normal());
+                        continue;
+                }
+                if (r == -EKEYREJECTED) {
+                        printf("%s# Unit %s could not be loaded.%s\n",
                                ansi_highlight_magenta(),
                                *name,
                                ansi_normal());
@@ -5384,7 +5464,7 @@ static int cat(int argc, char *argv[], void *userdata) {
                 }
                 if (r < 0)
                         return r;
-                else if (r == 0)
+                if (r == 0)
                         return -ENOENT;
 
                 if (first)
@@ -5953,7 +6033,7 @@ static int enable_sysv_units(const char *verb, char **args) {
                 if (!arg_quiet)
                         log_info("Executing: %s", l);
 
-                j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+                j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
                 if (j < 0)
                         return j;
                 if (j == 0) {
@@ -6781,7 +6861,8 @@ static int unit_file_create_new(
                 char **ret_new_path,
                 char **ret_tmp_path) {
 
-        char *tmp_new_path, *tmp_tmp_path, *ending;
+        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
+        const char *ending;
         int r;
 
         assert(unit_name);
@@ -6789,18 +6870,16 @@ static int unit_file_create_new(
         assert(ret_tmp_path);
 
         ending = strjoina(unit_name, suffix);
-        r = get_file_to_edit(paths, ending, &tmp_new_path);
+        r = get_file_to_edit(paths, ending, &new_path);
         if (r < 0)
                 return r;
 
-        r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
-        if (r < 0) {
-                free(tmp_new_path);
+        r = create_edit_temp_file(new_path, new_path, &tmp_path);
+        if (r < 0)
                 return r;
-        }
 
-        *ret_new_path = tmp_new_path;
-        *ret_tmp_path = tmp_tmp_path;
+        *ret_new_path = TAKE_PTR(new_path);
+        *ret_tmp_path = TAKE_PTR(tmp_path);
 
         return 0;
 }
@@ -6812,7 +6891,7 @@ static int unit_file_create_copy(
                 char **ret_new_path,
                 char **ret_tmp_path) {
 
-        char *tmp_new_path, *tmp_tmp_path;
+        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
         int r;
 
         assert(fragment_path);
@@ -6820,33 +6899,26 @@ static int unit_file_create_copy(
         assert(ret_new_path);
         assert(ret_tmp_path);
 
-        r = get_file_to_edit(paths, unit_name, &tmp_new_path);
+        r = get_file_to_edit(paths, unit_name, &new_path);
         if (r < 0)
                 return r;
 
-        if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
+        if (!path_equal(fragment_path, new_path) && access(new_path, F_OK) >= 0) {
                 char response;
 
-                r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
-                if (r < 0) {
-                        free(tmp_new_path);
+                r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", new_path, fragment_path);
+                if (r < 0)
                         return r;
-                }
-                if (response != 'y') {
-                        log_warning("%s ignored", unit_name);
-                        free(tmp_new_path);
-                        return -EKEYREJECTED;
-                }
+                if (response != 'y')
+                        return log_warning_errno(SYNTHETIC_ERRNO(EKEYREJECTED), "%s skipped.", unit_name);
         }
 
-        r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
-        if (r < 0) {
-                free(tmp_new_path);
+        r = create_edit_temp_file(new_path, fragment_path, &tmp_path);
+        if (r < 0)
                 return r;
-        }
 
-        *ret_new_path = tmp_new_path;
-        *ret_tmp_path = tmp_tmp_path;
+        *ret_new_path = TAKE_PTR(new_path);
+        *ret_tmp_path = TAKE_PTR(tmp_path);
 
         return 0;
 }
@@ -6856,7 +6928,7 @@ static int run_editor(char **paths) {
 
         assert(paths);
 
-        r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
+        r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_WAIT, NULL);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -6885,6 +6957,7 @@ static int run_editor(char **paths) {
                         n_editor_args = strv_length(editor_args);
                         argc += n_editor_args - 1;
                 }
+
                 args = newa(const char*, argc + 1);
 
                 if (n_editor_args > 0) {
@@ -6893,10 +6966,8 @@ static int run_editor(char **paths) {
                                 args[i] = editor_args[i];
                 }
 
-                STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
-                        args[i] = *tmp_path;
-                        i++;
-                }
+                STRV_FOREACH_PAIR(original_path, tmp_path, paths)
+                        args[i++] = *tmp_path;
                 args[i] = NULL;
 
                 if (n_editor_args > 0)
@@ -6938,7 +7009,15 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                 _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL, *tmp_name = NULL;
                 const char *unit_name;
 
-                r = unit_find_paths(bus, *name, &lp, &path, NULL);
+                r = unit_find_paths(bus, *name, &lp, false, &path, NULL);
+                if (r == -EKEYREJECTED) {
+                        /* If loading of the unit failed server side complete, then the server won't tell us the unit
+                         * file path. In that case, find the file client side. */
+                        log_debug_errno(r, "Unit '%s' was not loaded correctly, retrying client-side.", *name);
+                        r = unit_find_paths(bus, *name, &lp, true, &path, NULL);
+                }
+                if (r == -ERFKILL)
+                        return log_error_errno(r, "Unit '%s' masked, cannot edit.", *name);
                 if (r < 0)
                         return r;
 
@@ -6946,10 +7025,10 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                         assert(!path);
 
                         if (!arg_force) {
-                                log_error("Run 'systemctl edit%s --force %s' to create a new unit.",
-                                          arg_scope == UNIT_FILE_GLOBAL ? " --global" :
-                                          arg_scope == UNIT_FILE_USER ? " --user" : "",
-                                          *name);
+                                log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.",
+                                         arg_scope == UNIT_FILE_GLOBAL ? " --global" :
+                                         arg_scope == UNIT_FILE_USER ? " --user" : "",
+                                         *name);
                                 return -ENOENT;
                         }
 
@@ -6989,6 +7068,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                 r = strv_push_pair(paths, new_path, tmp_path);
                 if (r < 0)
                         return log_oom();
+
                 new_path = tmp_path = NULL;
         }
 
@@ -7029,7 +7109,6 @@ static int edit(int argc, char *argv[], void *userdata) {
                 r = unit_is_masked(bus, &lp, *tmp);
                 if (r < 0)
                         return r;
-
                 if (r > 0) {
                         log_error("Cannot edit %s: unit is masked.", *tmp);
                         return -EINVAL;
@@ -7501,7 +7580,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
         arg_ask_password = true;
 
-        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir.::", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -7817,6 +7896,14 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 return log_oom();
                         break;
 
+                case '.':
+                        /* Output an error mimicking getopt, and print a hint afterwards */
+                        log_error("%s: invalid option -- '.'", program_invocation_name);
+                        log_notice("Hint: to specify units starting with a dash, use \"--\":\n"
+                                   "      %s [OPTIONS...] {COMMAND} -- -.%s ...",
+                                   program_invocation_name, optarg ?: "mount");
+                        _fallthrough_;
+
                 case '?':
                         return -EINVAL;
 
@@ -8251,6 +8338,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 /* Hmm, so some other init system is running, we need to forward this request to
                                  * it. For now we simply guess that it is Upstart. */
 
+                                (void) rlimit_nofile_safe();
                                 execv(TELINIT, argv);
 
                                 return log_error_errno(SYNTHETIC_ERRNO(EIO),
@@ -8635,7 +8723,7 @@ static int logind_cancel_shutdown(void) {
 #endif
 }
 
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
         int r;
 
         argv_cmdline = argv[0];
index b026b5c5517e728b50ac76b0c9ab82cdd2a79831..05c38008cf6dcbd9f0d26c59952adc7df50ff2ef 100644 (file)
 #  error "Do not include _sd-common.h directly; it is a private header."
 #endif
 
+typedef void (*_sd_destroy_t)(void *userdata);
+
 #ifndef _sd_printf_
 #  if __GNUC__ >= 4
-#    define _sd_printf_(a,b) __attribute__ ((__format__(printf, a, b)))
+#    define _sd_printf_(a,b) __attribute__((__format__(printf, a, b)))
 #  else
 #    define _sd_printf_(a,b)
 #  endif
index 220ddb99eceecf28ac5b60c43897b71dc5e83270..4c1acab9f3af876702a79fb864e9fbeb965b8807 100644 (file)
@@ -107,7 +107,7 @@ typedef int (*sd_bus_property_set_t) (sd_bus *bus, const char *path, const char
 typedef int (*sd_bus_object_find_t) (sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error);
 typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error);
 typedef int (*sd_bus_track_handler_t) (sd_bus_track *track, void *userdata);
-typedef void (*sd_bus_destroy_t)(void *userdata);
+typedef _sd_destroy_t sd_bus_destroy_t;
 
 #include "sd-bus-protocol.h"
 #include "sd-bus-vtable.h"
index b15cade20a521d9e15be012273e0be28c159edff..787a12f2416b7fe16565abbe0015e827807ffc51 100644 (file)
@@ -77,7 +77,7 @@ typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si,
 typedef void* sd_event_child_handler_t;
 #endif
 typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata);
-typedef void (*sd_event_destroy_t)(void *userdata);
+typedef _sd_destroy_t sd_event_destroy_t;
 
 int sd_event_default(sd_event **e);
 
index e1b89559a8bf095d582b219a15566cd86efd03b9..30be5b113ca36e6c40241b72873536cebd37272a 100644 (file)
@@ -39,7 +39,7 @@ typedef enum {SD_GENL_ID_CTRL, SD_GENL_WIREGUARD, SD_GENL_FOU} sd_genl_family;
 /* callback */
 
 typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
-typedef void (*sd_netlink_destroy_t)(void *userdata);
+typedef _sd_destroy_t sd_netlink_destroy_t;
 
 /* bus */
 int sd_netlink_new_from_netlink(sd_netlink **nl, int fd);
@@ -179,6 +179,8 @@ int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message
 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);
+int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags);
+int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, unsigned *flags);
 
 /* genl */
 int sd_genl_socket_open(sd_netlink **nl);
index 089fcdee37634b33f683f9001cef06b69fc031ed..d78e8db257ca3e047a5f3ca9233ddf316dd2153e 100644 (file)
@@ -42,7 +42,7 @@ typedef struct sd_resolve_query sd_resolve_query;
 /* A callback on completion */
 typedef int (*sd_resolve_getaddrinfo_handler_t)(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata);
 typedef int (*sd_resolve_getnameinfo_handler_t)(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata);
-typedef void (*sd_resolve_destroy_t)(void *userdata);
+typedef _sd_destroy_t sd_resolve_destroy_t;
 
 enum {
         SD_RESOLVE_GET_HOST    = 1 << 0,
@@ -101,11 +101,11 @@ int sd_resolve_getaddrinfo(sd_resolve *resolve, sd_resolve_query **q, const char
  * if you want to query the hostname (resp. the service name). */
 int sd_resolve_getnameinfo(sd_resolve *resolve, sd_resolve_query **q, const struct sockaddr *sa, socklen_t salen, int flags, uint64_t get, sd_resolve_getnameinfo_handler_t callback, void *userdata);
 
-sd_resolve_query *sd_resolve_query_ref(sd_resolve_queryq);
-sd_resolve_query *sd_resolve_query_unref(sd_resolve_queryq);
+sd_resolve_query *sd_resolve_query_ref(sd_resolve_query *q);
+sd_resolve_query *sd_resolve_query_unref(sd_resolve_query *q);
 
 /* Returns non-zero when the query operation specified by q has been completed. */
-int sd_resolve_query_is_done(sd_resolve_query*q);
+int sd_resolve_query_is_done(sd_resolve_query *q);
 
 void *sd_resolve_query_get_userdata(sd_resolve_query *q);
 void *sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata);
index c2326ee9b81f852aab416dfef1bc7376fe93424e..df28bcfd720df874fcacb4ad18c8e430353e799d 100644 (file)
@@ -8,18 +8,21 @@
 #include "copy.h"
 #include "def.h"
 #include "fd-util.h"
-#include "fileio-label.h"
+#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "hashmap.h"
+#include "main-func.h"
 #include "pager.h"
 #include "path-util.h"
 #include "pretty-print.h"
+#include "set.h"
 #include "selinux-util.h"
 #include "smack-util.h"
 #include "specifier.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util-label.h"
 #include "uid-range.h"
 #include "user-util.h"
 #include "utf8.h"
@@ -68,13 +71,28 @@ static OrderedHashmap *users = NULL, *groups = NULL;
 static OrderedHashmap *todo_uids = NULL, *todo_gids = NULL;
 static OrderedHashmap *members = NULL;
 
-static Hashmap *database_uid = NULL, *database_user = NULL;
-static Hashmap *database_gid = NULL, *database_group = NULL;
+static Hashmap *database_by_uid = NULL, *database_by_username = NULL;
+static Hashmap *database_by_gid = NULL, *database_by_groupname = NULL;
+static Set *database_users = NULL, *database_groups = NULL;
 
 static uid_t search_uid = UID_INVALID;
 static UidRange *uid_range = NULL;
 static unsigned n_uid_range = 0;
 
+STATIC_DESTRUCTOR_REGISTER(groups, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(users, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(members, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(todo_uids, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(todo_gids, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(database_by_uid, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(database_by_username, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(database_users, set_free_freep);
+STATIC_DESTRUCTOR_REGISTER(database_by_gid, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(database_by_groupname, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep);
+STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+
 static int load_user_database(void) {
         _cleanup_fclose_ FILE *f = NULL;
         const char *passwd_path;
@@ -86,11 +104,15 @@ static int load_user_database(void) {
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
 
-        r = hashmap_ensure_allocated(&database_user, &string_hash_ops);
+        r = hashmap_ensure_allocated(&database_by_username, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        r = hashmap_ensure_allocated(&database_uid, NULL);
+        r = hashmap_ensure_allocated(&database_by_uid, NULL);
+        if (r < 0)
+                return r;
+
+        r = set_ensure_allocated(&database_users, NULL);
         if (r < 0)
                 return r;
 
@@ -102,21 +124,19 @@ static int load_user_database(void) {
                 if (!n)
                         return -ENOMEM;
 
-                k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid));
-                if (k < 0 && k != -EEXIST) {
+                k = set_put(database_users, n);
+                if (k < 0) {
                         free(n);
                         return k;
                 }
 
-                q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid), n);
-                if (q < 0 && q != -EEXIST) {
-                        if (k <= 0)
-                                free(n);
-                        return q;
-                }
+                k = hashmap_put(database_by_username, n, UID_TO_PTR(pw->pw_uid));
+                if (k < 0 && k != -EEXIST)
+                        return k;
 
-                if (k <= 0 && q <= 0)
-                        free(n);
+                q = hashmap_put(database_by_uid, UID_TO_PTR(pw->pw_uid), n);
+                if (q < 0 && q != -EEXIST)
+                        return q;
         }
         return r;
 }
@@ -132,16 +152,19 @@ static int load_group_database(void) {
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
 
-        r = hashmap_ensure_allocated(&database_group, &string_hash_ops);
+        r = hashmap_ensure_allocated(&database_by_groupname, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        r = hashmap_ensure_allocated(&database_gid, NULL);
+        r = hashmap_ensure_allocated(&database_by_gid, NULL);
         if (r < 0)
                 return r;
 
-        errno = 0;
-        while ((gr = fgetgrent(f))) {
+        r = set_ensure_allocated(&database_groups, NULL);
+        if (r < 0)
+                return r;
+
+        while ((r = fgetgrent_sane(f, &gr)) > 0) {
                 char *n;
                 int k, q;
 
@@ -149,28 +172,21 @@ static int load_group_database(void) {
                 if (!n)
                         return -ENOMEM;
 
-                k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid));
-                if (k < 0 && k != -EEXIST) {
+                k = set_put(database_groups, n);
+                if (k < 0) {
                         free(n);
                         return k;
                 }
 
-                q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid), n);
-                if (q < 0 && q != -EEXIST) {
-                        if (k <= 0)
-                                free(n);
-                        return q;
-                }
-
-                if (k <= 0 && q <= 0)
-                        free(n);
+                k = hashmap_put(database_by_groupname, n, GID_TO_PTR(gr->gr_gid));
+                if (k < 0 && k != -EEXIST)
+                        return k;
 
-                errno = 0;
+                q = hashmap_put(database_by_gid, GID_TO_PTR(gr->gr_gid), n);
+                if (q < 0 && q != -EEXIST)
+                        return q;
         }
-        if (!IN_SET(errno, 0, ENOENT))
-                return -errno;
-
-        return 0;
+        return r;
 }
 
 static int make_backup(const char *target, const char *x) {
@@ -822,11 +838,11 @@ static int uid_is_ok(uid_t uid, const char *name, bool check_with_gid) {
         }
 
         /* Let's check the files directly */
-        if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
+        if (hashmap_contains(database_by_uid, UID_TO_PTR(uid)))
                 return 0;
 
         if (check_with_gid) {
-                n = hashmap_get(database_gid, GID_TO_PTR(uid));
+                n = hashmap_get(database_by_gid, GID_TO_PTR(uid));
                 if (n && !streq(n, name))
                         return 0;
         }
@@ -929,7 +945,7 @@ static int add_user(Item *i) {
         assert(i);
 
         /* Check the database directly */
-        z = hashmap_get(database_user, i->name);
+        z = hashmap_get(database_by_username, i->name);
         if (z) {
                 log_debug("User %s already exists.", i->name);
                 i->uid = PTR_TO_UID(z);
@@ -1046,10 +1062,10 @@ static int gid_is_ok(gid_t gid) {
         if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)))
                 return 0;
 
-        if (hashmap_contains(database_gid, GID_TO_PTR(gid)))
+        if (hashmap_contains(database_by_gid, GID_TO_PTR(gid)))
                 return 0;
 
-        if (hashmap_contains(database_uid, UID_TO_PTR(gid)))
+        if (hashmap_contains(database_by_uid, UID_TO_PTR(gid)))
                 return 0;
 
         if (!arg_root) {
@@ -1078,7 +1094,7 @@ static int add_group(Item *i) {
         assert(i);
 
         /* Check the database directly */
-        z = hashmap_get(database_group, i->name);
+        z = hashmap_get(database_by_groupname, i->name);
         if (z) {
                 log_debug("Group %s already exists.", i->name);
                 i->gid = PTR_TO_GID(z);
@@ -1227,10 +1243,9 @@ static int process_item(Item *i) {
         }
 }
 
-static void item_free(Item *i) {
-
+static Item* item_free(Item *i) {
         if (!i)
-                return;
+                return NULL;
 
         free(i->name);
         free(i->uid_path);
@@ -1238,10 +1253,11 @@ static void item_free(Item *i) {
         free(i->description);
         free(i->home);
         free(i->shell);
-        free(i);
+        return mfree(i);
 }
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_hash_ops, char, string_hash_func, string_compare_func, Item, item_free);
 
 static int add_implicit(void) {
         char *g, **l;
@@ -1256,7 +1272,7 @@ static int add_implicit(void) {
                         if (!ordered_hashmap_get(users, *m)) {
                                 _cleanup_(item_freep) Item *j = NULL;
 
-                                r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops);
+                                r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops);
                                 if (r < 0)
                                         return log_oom();
 
@@ -1281,7 +1297,7 @@ static int add_implicit(void) {
                       ordered_hashmap_get(groups, g))) {
                         _cleanup_(item_freep) Item *j = NULL;
 
-                        r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops);
+                        r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops);
                         if (r < 0)
                                 return log_oom();
 
@@ -1346,6 +1362,8 @@ static bool item_equal(Item *a, Item *b) {
         return true;
 }
 
+DEFINE_PRIVATE_HASH_OPS_FULL(members_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
+
 static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         static const Specifier specifier_table[] = {
@@ -1536,7 +1554,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                         return -EINVAL;
                 }
 
-                r = ordered_hashmap_ensure_allocated(&members, &string_hash_ops);
+                r = ordered_hashmap_ensure_allocated(&members, &members_hash_ops);
                 if (r < 0)
                         return log_oom();
 
@@ -1578,7 +1596,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                         return -EINVAL;
                 }
 
-                r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops);
+                r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops);
                 if (r < 0)
                         return log_oom();
 
@@ -1629,7 +1647,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                         return -EINVAL;
                 }
 
-                r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops);
+                r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops);
                 if (r < 0)
                         return log_oom();
 
@@ -1731,27 +1749,6 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
         return r;
 }
 
-static void free_database(Hashmap *by_name, Hashmap *by_id) {
-        char *name;
-
-        for (;;) {
-                name = hashmap_first(by_id);
-                if (!name)
-                        break;
-
-                hashmap_remove(by_name, name);
-
-                hashmap_steal_first_key(by_id);
-                free(name);
-        }
-
-        while ((name = hashmap_steal_first_key(by_name)))
-                free(name);
-
-        hashmap_free(by_name);
-        hashmap_free(by_id);
-}
-
 static int cat_config(void) {
         _cleanup_strv_free_ char **files = NULL;
         int r;
@@ -1919,31 +1916,26 @@ static int read_config_files(char **args) {
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_close_ int lock = -1;
         Iterator iterator;
-        char *n, **v;
         Item *i;
         int r;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                goto finish;
+                return r;
 
         log_setup_service();
 
-        if (arg_cat_config) {
-                r = cat_config();
-                goto finish;
-        }
+        if (arg_cat_config)
+                return cat_config();
 
         umask(0022);
 
         r = mac_selinux_init();
-        if (r < 0) {
-                log_error_errno(r, "SELinux setup failed: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "SELinux setup failed: %m");
 
         /* If command line arguments are specified along with --replace, read all
          * configuration files and insert the positional arguments at the specified
@@ -1956,48 +1948,38 @@ int main(int argc, char *argv[]) {
         else
                 r = parse_arguments(argv + optind);
         if (r < 0)
-                goto finish;
+                return r;
 
         /* 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 (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0)
+                return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m");
 
         if (!uid_range) {
                 /* Default to default range of 1..SYSTEM_UID_MAX */
                 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
-                if (r < 0) {
-                        log_oom();
-                        goto finish;
-                }
+                if (r < 0)
+                        return log_oom();
         }
 
         r = add_implicit();
         if (r < 0)
-                goto finish;
+                return r;
 
         lock = take_etc_passwd_lock(arg_root);
-        if (lock < 0) {
-                log_error_errno(lock, "Failed to take /etc/passwd lock: %m");
-                goto finish;
-        }
+        if (lock < 0)
+                return log_error_errno(lock, "Failed to take /etc/passwd lock: %m");
 
         r = load_user_database();
-        if (r < 0) {
-                log_error_errno(r, "Failed to load user database: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to load user database: %m");
 
         r = load_group_database();
-        if (r < 0) {
-                log_error_errno(r, "Failed to read group database: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to read group database: %m");
 
         ORDERED_HASHMAP_FOREACH(i, groups, iterator)
                 (void) process_item(i);
@@ -2007,29 +1989,9 @@ int main(int argc, char *argv[]) {
 
         r = write_files();
         if (r < 0)
-                log_error_errno(r, "Failed to write files: %m");
-
-finish:
-        pager_close();
-
-        ordered_hashmap_free_with_destructor(groups, item_free);
-        ordered_hashmap_free_with_destructor(users, item_free);
+                return log_error_errno(r, "Failed to write files: %m");
 
-        while ((v = ordered_hashmap_steal_first_key_and_value(members, (void **) &n))) {
-                strv_free(v);
-                free(n);
-        }
-        ordered_hashmap_free(members);
-
-        ordered_hashmap_free(todo_uids);
-        ordered_hashmap_free(todo_gids);
-
-        free_database(database_user, database_uid);
-        free_database(database_group, database_gid);
-
-        free(uid_range);
-
-        free(arg_root);
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index ade905733ed910b3266629ccbf79f7c79000cc23..9863ecc8f034aa279607f5c1d01ab75aec90aa4e 100644 (file)
@@ -156,6 +156,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-dev-setup.c'],
+         [],
+         []],
+
         [['src/test/test-capability.c'],
          [],
          [libcap]],
@@ -173,6 +177,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-static-destruct.c'],
+         [],
+         []],
+
         [['src/test/test-sigbus.c'],
          [],
          []],
@@ -213,6 +221,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-mountpoint-util.c'],
+         [],
+         []],
+
         [['src/test/test-exec-util.c'],
          [],
          []],
@@ -638,6 +650,11 @@ tests += [
          [],
          []],
 
+        [['src/test/test-ip-protocol-list.c',
+          shared_generated_gperf_headers],
+         [],
+         []],
+
         [['src/test/test-journal-importer.c'],
          [],
          []],
index a8d413533e43f2b9d4d572bd2a6b6d47c326e937..df879747f5643871235d57fc2c65a51c352cf689 100644 (file)
@@ -7,8 +7,8 @@
 
 #include "acl-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 
 static void test_add_acls_for_user(void) {
index 9803c53f212a5caac8996132ef4073d3f29a8253..3005fc1b696bc47eb151d0f1154871c25bb158e8 100644 (file)
@@ -4,8 +4,8 @@
 #include <string.h>
 
 #include "macro.h"
+#include "missing_network.h"
 #include "string-util.h"
-#include "util.h"
 
 _unused_ \
 static const struct arphrd_name* lookup_arphrd(register const char *str, register GPERF_LEN_TYPE len);
index 7c7dfe62da3fdd2dc91afa39d2a32b3849fa7e1e..4f5307889ea5c5e1049d59214f3883e62450b904 100644 (file)
@@ -3,8 +3,8 @@
 #include <unistd.h>
 
 #include "async.h"
-#include "fileio.h"
 #include "macro.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static bool test_async = false;
@@ -32,7 +32,7 @@ int main(int argc, char *argv[]) {
         assert_se(fcntl(fd, F_GETFD) == -1);
         assert_se(test_async);
 
-        unlink(name);
+        (void) unlink(name);
 
         return 0;
 }
index 5bfcc385d9e45584ddca6e9e588bfaf1dee389b5..dae85f2f91c5ab619405a6579a774c035d02a327 100644 (file)
@@ -20,7 +20,7 @@
 static uid_t test_uid = -1;
 static gid_t test_gid = -1;
 
-#ifdef __SANITIZE_ADDRESS__
+#if HAS_FEATURE_ADDRESS_SANITIZER
 /* Keep CAP_SYS_PTRACE when running under Address Sanitizer */
 static const uint64_t test_flags = UINT64_C(1) << CAP_SYS_PTRACE;
 #else
index 143e7aa42477edb1f7c72f6a70111369d3511754..7f6c0c27722195cdead667ee13005fd13bc764b2 100644 (file)
@@ -30,7 +30,7 @@ static void log_cgroup_mask(CGroupMask got, CGroupMask expected) {
 static int test_cgroup_mask(void) {
         _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
-        Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep;
+        Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep, *nomem_parent, *nomem_leaf;
         int r;
         CGroupMask cpu_accounting_mask = get_cpu_accounting_mask();
 
@@ -68,11 +68,15 @@ static int test_cgroup_mask(void) {
         assert_se(manager_load_startable_unit_or_warn(m, "daughter.service", NULL, &daughter) >= 0);
         assert_se(manager_load_startable_unit_or_warn(m, "grandchild.service", NULL, &grandchild) >= 0);
         assert_se(manager_load_startable_unit_or_warn(m, "parent-deep.slice", NULL, &parent_deep) >= 0);
+        assert_se(manager_load_startable_unit_or_warn(m, "nomem.slice", NULL, &nomem_parent) >= 0);
+        assert_se(manager_load_startable_unit_or_warn(m, "nomemleaf.service", NULL, &nomem_leaf) >= 0);
         assert_se(UNIT_DEREF(son->slice) == parent);
         assert_se(UNIT_DEREF(daughter->slice) == parent);
         assert_se(UNIT_DEREF(parent_deep->slice) == parent);
         assert_se(UNIT_DEREF(grandchild->slice) == parent_deep);
+        assert_se(UNIT_DEREF(nomem_leaf->slice) == nomem_parent);
         root = UNIT_DEREF(parent->slice);
+        assert_se(UNIT_DEREF(nomem_parent->slice) == root);
 
         /* Verify per-unit cgroups settings. */
         ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(son), CGROUP_MASK_CPU);
@@ -80,6 +84,8 @@ static int test_cgroup_mask(void) {
         ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(grandchild), 0);
         ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(parent_deep), CGROUP_MASK_MEMORY);
         ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
+        ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(nomem_parent), 0);
+        ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
         ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(root), 0);
 
         /* Verify aggregation of member masks */
@@ -88,6 +94,8 @@ static int test_cgroup_mask(void) {
         ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(grandchild), 0);
         ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(parent_deep), 0);
         ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(parent), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY));
+        ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(nomem_parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
+        ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(nomem_leaf), 0);
         ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(root), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
 
         /* Verify aggregation of sibling masks. */
@@ -96,6 +104,8 @@ static int test_cgroup_mask(void) {
         ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(grandchild), 0);
         ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(parent_deep), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY));
         ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(parent), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+        ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(nomem_parent), (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+        ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
         ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(root), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
 
         /* Verify aggregation of target masks. */
@@ -104,6 +114,8 @@ static int test_cgroup_mask(void) {
         ASSERT_CGROUP_MASK(unit_get_target_mask(grandchild), 0);
         ASSERT_CGROUP_MASK(unit_get_target_mask(parent_deep), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY) & m->cgroup_supported));
         ASSERT_CGROUP_MASK(unit_get_target_mask(parent), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
+        ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_parent), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported));
+        ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_leaf), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported));
         ASSERT_CGROUP_MASK(unit_get_target_mask(root), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
 
         return 0;
index 9211c996ac11f740cd4aa0698652b4cef5229652..5cdfd2dc54ebdb9f0dbf0bae15f3021b3ed20a88 100644 (file)
@@ -9,7 +9,7 @@
 #include "string-util.h"
 #include "util.h"
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
         char *path;
         char *c, *p;
 
index f635b4ff92aa5f2d76cb1aa2ae067e6876f428b1..305d44f568b001f01fd3a1f2ca9919e12d0199a8 100644 (file)
@@ -4,11 +4,11 @@
 
 #include "alloc-util.h"
 #include "chown-recursive.h"
-#include "fileio.h"
 #include "log.h"
 #include "rm-rf.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 
 static const uint8_t acl[] = {
         0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00,
index f5b9a727271e9255bd4dcf26377db26ddb30a4ce..018e679b4544962ddfe69022838a1439961e30d1 100644 (file)
@@ -12,6 +12,7 @@
 #include "fs-util.h"
 #include "log.h"
 #include "macro.h"
+#include "tmpfile-util.h"
 
 static void test_clock_is_localtime(void) {
         _cleanup_(unlink_tempfilep) char adjtime[] = "/tmp/test-adjtime.XXXXXX";
index 497becff731c62df97781fde9c1a3b5a1affdccb..2921338f62a8a52a53ecdca55fc14844ab7e5f14 100644 (file)
@@ -2,12 +2,12 @@
 
 #include "conf-parser.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "log.h"
 #include "macro.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void test_config_parse_path_one(const char *rvalue, const char *expected) {
index 4e265374ab116548305e565cba9e2b7365f2c95e..b17a1c53fe67d3509a02f93ef163bd346ba6d0ea 100644 (file)
@@ -15,6 +15,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index c8a83f0fc925cbcca9d619246075473ef94f4486..a4b96da0457331f1fa0d3c42c6620241ca4b4646 100644 (file)
@@ -7,7 +7,7 @@
 #include "parse-util.h"
 #include "strv.h"
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
         _cleanup_strv_free_ char **l = NULL;
         int n, i;
         usec_t duration = USEC_PER_SEC / 10;
diff --git a/src/test/test-dev-setup.c b/src/test/test-dev-setup.c
new file mode 100644 (file)
index 0000000..9414ea6
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "capability-util.h"
+#include "dev-setup.h"
+#include "fs-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "tmpfile-util.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_(rm_rf_physical_and_freep) char *p = NULL;
+        const char *f;
+        struct stat st;
+
+        if (have_effective_cap(CAP_DAC_OVERRIDE) <= 0)
+                return EXIT_TEST_SKIP;
+
+        assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0);
+
+        f = prefix_roota(p, "/run");
+        assert_se(mkdir(f, 0755) >= 0);
+
+        assert_se(make_inaccessible_nodes(p, 1, 1) >= 0);
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/reg");
+        assert_se(stat(f, &st) >= 0);
+        assert_se(S_ISREG(st.st_mode));
+        assert_se((st.st_mode & 07777) == 0000);
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/dir");
+        assert_se(stat(f, &st) >= 0);
+        assert_se(S_ISDIR(st.st_mode));
+        assert_se((st.st_mode & 07777) == 0000);
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/fifo");
+        assert_se(stat(f, &st) >= 0);
+        assert_se(S_ISFIFO(st.st_mode));
+        assert_se((st.st_mode & 07777) == 0000);
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/sock");
+        assert_se(stat(f, &st) >= 0);
+        assert_se(S_ISSOCK(st.st_mode));
+        assert_se((st.st_mode & 07777) == 0000);
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/chr");
+        if (stat(f, &st) < 0)
+                assert_se(errno == ENOENT);
+        else {
+                assert_se(S_ISCHR(st.st_mode));
+                assert_se((st.st_mode & 07777) == 0000);
+        }
+
+        f = prefix_roota(p, "/run/systemd/inaccessible/blk");
+        if (stat(f, &st) < 0)
+                assert_se(errno == ENOENT);
+        else {
+                assert_se(S_ISBLK(st.st_mode));
+                assert_se((st.st_mode & 07777) == 0000);
+        }
+
+        return EXIT_SUCCESS;
+}
index cbfe5ef390388623028d6dbe2ba1ebb8895e072e..ead5311705d63c8ac6e8665ce71297f35de98942 100644 (file)
@@ -6,39 +6,65 @@
 #include "string-util.h"
 #include "tests.h"
 
-static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
+static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret, int ret_ldh) {
         char buffer[buffer_sz];
         int r;
+        const char *w = what;
 
-        r = dns_label_unescape(&what, buffer, buffer_sz);
+        log_info("%s, %s, %zu, →%d/%d", what, expect, buffer_sz, ret, ret_ldh);
+
+        r = dns_label_unescape(&w, buffer, buffer_sz, 0);
         assert_se(r == ret);
+        if (r >= 0)
+                assert_se(streq(buffer, expect));
 
-        if (r < 0)
-                return;
+        w = what;
+        r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_LDH);
+        assert_se(r == ret_ldh);
+        if (r >= 0)
+                assert_se(streq(buffer, expect));
 
-        assert_se(streq(buffer, expect));
+        w = what;
+        r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_NO_ESCAPES);
+        const int ret_noe = strchr(what, '\\') ? -EINVAL : ret;
+        assert_se(r == ret_noe);
+        if (r >= 0)
+                assert_se(streq(buffer, expect));
 }
 
 static void test_dns_label_unescape(void) {
-        test_dns_label_unescape_one("hallo", "hallo", 6, 5);
-        test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS);
-        test_dns_label_unescape_one("", "", 10, 0);
-        test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12);
-        test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5);
-        test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL);
-        test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL);
-        test_dns_label_unescape_one("hallo\\032 ", "hallo  ", 20, 7);
-        test_dns_label_unescape_one(".", "", 20, 0);
-        test_dns_label_unescape_one("..", "", 20, -EINVAL);
-        test_dns_label_unescape_one(".foobar", "", 20, -EINVAL);
-        test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
-        test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL);
+        log_info("/* %s */", __func__);
+
+        test_dns_label_unescape_one("hallo", "hallo", 6, 5, 5);
+        test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS, -ENOBUFS);
+        test_dns_label_unescape_one("", "", 10, 0, 0);
+        test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12, -EINVAL);
+        test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5, 5);
+        test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL, -EINVAL);
+        test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL, -EINVAL);
+        test_dns_label_unescape_one("hallo\\032 ", "hallo  ", 20, 7, -EINVAL);
+        test_dns_label_unescape_one(".", "", 20, 0, 0);
+        test_dns_label_unescape_one("..", "", 20, -EINVAL, -EINVAL);
+        test_dns_label_unescape_one(".foobar", "", 20, -EINVAL, -EINVAL);
+        test_dns_label_unescape_one("foobar.", "foobar", 20, 6, 6);
+        test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL, -EINVAL);
+        test_dns_label_unescape_one("foo-bar", "foo-bar", 20, 7, 7);
+        test_dns_label_unescape_one("foo-", "foo-", 20, 4, -EINVAL);
+        test_dns_label_unescape_one("-foo", "-foo", 20, 4, -EINVAL);
+        test_dns_label_unescape_one("-foo-", "-foo-", 20, 5, -EINVAL);
+        test_dns_label_unescape_one("foo-.", "foo-", 20, 4, -EINVAL);
+        test_dns_label_unescape_one("foo.-", "foo", 20, 3, 3);
+        test_dns_label_unescape_one("foo\\032", "foo ", 20, 4, -EINVAL);
+        test_dns_label_unescape_one("foo\\045", "foo-", 20, 4, -EINVAL);
+        test_dns_label_unescape_one("głąb", "głąb", 20, 6, -EINVAL);
 }
 
 static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
         uint8_t buffer[buffer_sz];
         int r;
 
+        log_info("%s, %s, %zu, →%d", what, expect, buffer_sz, ret);
+
         r = dns_name_to_wire_format(what, buffer, buffer_sz, false);
         assert_se(r == ret);
 
@@ -80,6 +106,8 @@ static void test_dns_name_to_wire_format(void) {
                                      9, 'a', '1', '2', '3', '4', '5', '6', '7', '8',
                                      3, 'a', '1', '2', 0 };
 
+        log_info("/* %s */", __func__);
+
         test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0));
 
         test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1));
@@ -100,6 +128,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp
         const char *label;
         int r;
 
+        log_info("%s, %s, %s, %zu, %d, %d", what, expect1, expect2, buffer_sz, ret1, ret2);
+
         label = what + strlen(what);
 
         r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
@@ -114,6 +144,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp
 }
 
 static void test_dns_label_unescape_suffix(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0);
         test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS);
         test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);
@@ -139,6 +171,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
         _cleanup_free_ char *t = NULL;
         int r;
 
+        log_info("%s, %zu, %s, →%d", what, l, expect, ret);
+
         r = dns_label_escape_new(what, l, &t);
         assert_se(r == ret);
 
@@ -149,6 +183,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
 }
 
 static void test_dns_label_escape(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_label_escape_one("", 0, NULL, -EINVAL);
         test_dns_label_escape_one("hallo", 5, "hallo", 5);
         test_dns_label_escape_one("hallo", 6, "hallo\\000", 9);
@@ -159,7 +195,7 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in
         _cleanup_free_ char *t = NULL;
         int r;
 
-        r = dns_name_normalize(what, &t);
+        r = dns_name_normalize(what, 0, &t);
         assert_se(r == ret);
 
         if (r < 0)
@@ -320,7 +356,7 @@ static void test_dns_name_reverse(void) {
 static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) {
         _cleanup_free_ char *p = NULL;
 
-        assert_se(dns_name_concat(a, b, &p) == r);
+        assert_se(dns_name_concat(a, b, 0, &p) == r);
         assert_se(streq_ptr(p, result));
 }
 
@@ -339,46 +375,68 @@ static void test_dns_name_concat(void) {
         test_dns_name_concat_one(NULL, "foo", 0, "foo");
 }
 
-static void test_dns_name_is_valid_one(const char *s, int ret) {
+static void test_dns_name_is_valid_one(const char *s, int ret, int ret_ldh) {
+        log_info("%s, →%d", s, ret);
+
         assert_se(dns_name_is_valid(s) == ret);
+        assert_se(dns_name_is_valid_ldh(s) == ret_ldh);
 }
 
 static void test_dns_name_is_valid(void) {
-        test_dns_name_is_valid_one("foo", 1);
-        test_dns_name_is_valid_one("foo.", 1);
-        test_dns_name_is_valid_one("foo..", 0);
-        test_dns_name_is_valid_one("Foo", 1);
-        test_dns_name_is_valid_one("foo.bar", 1);
-        test_dns_name_is_valid_one("foo.bar.baz", 1);
-        test_dns_name_is_valid_one("", 1);
-        test_dns_name_is_valid_one("foo..bar", 0);
-        test_dns_name_is_valid_one(".foo.bar", 0);
-        test_dns_name_is_valid_one("foo.bar.", 1);
-        test_dns_name_is_valid_one("foo.bar..", 0);
-        test_dns_name_is_valid_one("\\zbar", 0);
-        test_dns_name_is_valid_one("ä", 1);
-        test_dns_name_is_valid_one("\n", 0);
+        log_info("/* %s */", __func__);
+
+        test_dns_name_is_valid_one("foo",               1, 1);
+        test_dns_name_is_valid_one("foo.",              1, 1);
+        test_dns_name_is_valid_one("foo..",             0, 0);
+        test_dns_name_is_valid_one("Foo",               1, 1);
+        test_dns_name_is_valid_one("foo.bar",           1, 1);
+        test_dns_name_is_valid_one("foo.bar.baz",       1, 1);
+        test_dns_name_is_valid_one("",                  1, 1);
+        test_dns_name_is_valid_one("foo..bar",          0, 0);
+        test_dns_name_is_valid_one(".foo.bar",          0, 0);
+        test_dns_name_is_valid_one("foo.bar.",          1, 1);
+        test_dns_name_is_valid_one("foo.bar..",         0, 0);
+        test_dns_name_is_valid_one("\\zbar",            0, 0);
+        test_dns_name_is_valid_one("ä",                 1, 0);
+        test_dns_name_is_valid_one("\n",                0, 0);
+
+        test_dns_name_is_valid_one("dash-",             1, 0);
+        test_dns_name_is_valid_one("-dash",             1, 0);
+        test_dns_name_is_valid_one("dash-dash",         1, 1);
+        test_dns_name_is_valid_one("foo.dash-",         1, 0);
+        test_dns_name_is_valid_one("foo.-dash",         1, 0);
+        test_dns_name_is_valid_one("foo.dash-dash",     1, 1);
+        test_dns_name_is_valid_one("foo.dash-.bar",     1, 0);
+        test_dns_name_is_valid_one("foo.-dash.bar",     1, 0);
+        test_dns_name_is_valid_one("foo.dash-dash.bar", 1, 1);
+        test_dns_name_is_valid_one("dash-.bar",         1, 0);
+        test_dns_name_is_valid_one("-dash.bar",         1, 0);
+        test_dns_name_is_valid_one("dash-dash.bar",     1, 1);
+        test_dns_name_is_valid_one("-.bar",             1, 0);
+        test_dns_name_is_valid_one("foo.-",             1, 0);
 
         /* 256 characters */
-        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0);
+        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0, 0);
 
         /* 255 characters */
-        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0);
+        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0, 0);
 
         /* 254 characters */
-        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0);
+        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0, 0);
 
         /* 253 characters */
-        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1);
+        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1, 1);
 
         /* label of 64 chars length */
-        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0);
+        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0, 0);
 
         /* label of 63 chars length */
-        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1);
+        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1, 1);
 }
 
 static void test_dns_service_name_is_valid(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(dns_service_name_is_valid("Lennart's Compüter"));
         assert_se(dns_service_name_is_valid("piff.paff"));
 
@@ -390,6 +448,7 @@ static void test_dns_service_name_is_valid(void) {
 }
 
 static void test_dns_srv_type_is_valid(void) {
+        log_info("/* %s */", __func__);
 
         assert_se(dns_srv_type_is_valid("_http._tcp"));
         assert_se(dns_srv_type_is_valid("_foo-bar._tcp"));
@@ -413,6 +472,7 @@ static void test_dns_srv_type_is_valid(void) {
 }
 
 static void test_dnssd_srv_type_is_valid(void) {
+        log_info("/* %s */", __func__);
 
         assert_se(dnssd_srv_type_is_valid("_http._tcp"));
         assert_se(dnssd_srv_type_is_valid("_foo-bar._tcp"));
@@ -439,6 +499,8 @@ static void test_dnssd_srv_type_is_valid(void) {
 static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) {
         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
 
+        log_info("%s, %s, %s, →%d, %s", a, b, c, r, d);
+
         assert_se(dns_service_join(a, b, c, &t) == r);
         assert_se(streq_ptr(t, d));
 
@@ -452,6 +514,8 @@ static void test_dns_service_join_one(const char *a, const char *b, const char *
 }
 
 static void test_dns_service_join(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_service_join_one("", "", "", -EINVAL, NULL);
         test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL);
         test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL);
@@ -469,6 +533,8 @@ static void test_dns_service_join(void) {
 static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) {
         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
 
+        log_info("%s, %s, %s, %s, →%d", joined, a, b, c, r);
+
         assert_se(dns_service_split(joined, &x, &y, &z) == r);
         assert_se(streq_ptr(x, a));
         assert_se(streq_ptr(y, b));
@@ -485,6 +551,8 @@ static void test_dns_service_split_one(const char *joined, const char *a, const
 }
 
 static void test_dns_service_split(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_service_split_one("", NULL, NULL, ".", 0);
         test_dns_service_split_one("foo", NULL, NULL, "foo", 0);
         test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0);
@@ -497,11 +565,15 @@ static void test_dns_service_split(void) {
 static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) {
         _cleanup_free_ char *s = NULL;
 
+        log_info("%s, %s, %s, →%s", name, old_suffix, new_suffix, result);
+
         assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r);
         assert_se(streq_ptr(s, result));
 }
 
 static void test_dns_name_change_suffix(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo");
         test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff");
         test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff");
@@ -516,11 +588,15 @@ static void test_dns_name_change_suffix(void) {
 static void test_dns_name_suffix_one(const char *name, unsigned n_labels, const char *result, int ret) {
         const char *p = NULL;
 
+        log_info("%s, %d, →%s, %d", name, n_labels, result, ret);
+
         assert_se(ret == dns_name_suffix(name, n_labels, &p));
         assert_se(streq_ptr(p, result));
 }
 
 static void test_dns_name_suffix(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_name_suffix_one("foo.bar", 2, "foo.bar", 0);
         test_dns_name_suffix_one("foo.bar", 1, "bar", 1);
         test_dns_name_suffix_one("foo.bar", 0, "", 2);
@@ -538,10 +614,14 @@ static void test_dns_name_suffix(void) {
 }
 
 static void test_dns_name_count_labels_one(const char *name, int n) {
+        log_info("%s, →%d", name, n);
+
         assert_se(dns_name_count_labels(name) == n);
 }
 
 static void test_dns_name_count_labels(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_name_count_labels_one("foo.bar.quux.", 3);
         test_dns_name_count_labels_one("foo.bar.quux", 3);
         test_dns_name_count_labels_one("foo.bar.", 2);
@@ -554,10 +634,14 @@ static void test_dns_name_count_labels(void) {
 }
 
 static void test_dns_name_equal_skip_one(const char *a, unsigned n_labels, const char *b, int ret) {
+        log_info("%s, %u, %s, →%d", a, n_labels, b, ret);
+
         assert_se(dns_name_equal_skip(a, n_labels, b) == ret);
 }
 
 static void test_dns_name_equal_skip(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_name_equal_skip_one("foo", 0, "bar", 0);
         test_dns_name_equal_skip_one("foo", 0, "foo", 1);
         test_dns_name_equal_skip_one("foo", 1, "foo", 0);
@@ -585,6 +669,8 @@ static void test_dns_name_equal_skip(void) {
 }
 
 static void test_dns_name_compare_func(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(dns_name_compare_func("", "") == 0);
         assert_se(dns_name_compare_func("", ".") == 0);
         assert_se(dns_name_compare_func(".", "") == 0);
@@ -600,11 +686,15 @@ static void test_dns_name_compare_func(void) {
 static void test_dns_name_common_suffix_one(const char *a, const char *b, const char *result) {
         const char *c;
 
+        log_info("%s, %s, →%s", a, b, result);
+
         assert_se(dns_name_common_suffix(a, b, &c) >= 0);
         assert_se(streq(c, result));
 }
 
 static void test_dns_name_common_suffix(void) {
+        log_info("/* %s */", __func__);
+
         test_dns_name_common_suffix_one("", "", "");
         test_dns_name_common_suffix_one("foo", "", "");
         test_dns_name_common_suffix_one("", "foo", "");
@@ -639,6 +729,7 @@ static void test_dns_name_apply_idna(void) {
 #else
         const int ret = 0;
 #endif
+        log_info("/* %s */", __func__);
 
         /* IDNA2008 forbids names with hyphens in third and fourth positions
          * (https://tools.ietf.org/html/rfc5891#section-4.2.3.1).
@@ -676,6 +767,8 @@ static void test_dns_name_apply_idna(void) {
 }
 
 static void test_dns_name_is_valid_or_address(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(dns_name_is_valid_or_address(NULL) == 0);
         assert_se(dns_name_is_valid_or_address("") == 0);
         assert_se(dns_name_is_valid_or_address("foobar") > 0);
index a8e9d9c2a1f87c78c9c326b4be95f4916b40e494..2115061addc1b1a13f633c3ae1e07dcf24e6d409 100644 (file)
@@ -759,7 +759,7 @@ int main(int argc, char *argv[]) {
 
         test_setup_logging(LOG_DEBUG);
 
-#ifdef __SANITIZE_ADDRESS__
+#if HAS_FEATURE_ADDRESS_SANITIZER
         if (is_run_on_travis_ci()) {
                 log_notice("Running on TravisCI under ASan, skipping, see https://github.com/systemd/systemd/issues/10696");
                 return EXIT_TEST_SKIP;
@@ -781,7 +781,7 @@ int main(int argc, char *argv[]) {
                 return log_tests_skipped("cgroupfs not available");
 
         assert_se(runtime_dir = setup_fake_runtime_dir());
-        test_execute_path = path_join(NULL, get_testdata_dir(), "test-execute");
+        test_execute_path = path_join(get_testdata_dir(), "test-execute");
         assert_se(set_unit_path(test_execute_path) >= 0);
 
         /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
index 157dc88320789b43c9f4838b191924da3c3d0e9b..7a0a2ad7d8b35fe1ca7bcc8489bf8b193e2f3896 100644 (file)
 #include "path-util.h"
 #include "process-util.h"
 #include "random-util.h"
+#include "serialize.h"
 #include "string-util.h"
-#include "util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
+#include "util.h"
 
 static void test_close_many(void) {
         int fds[3];
index 7d68a6b966f6ffaae909b1c183c3c9d7988fe741..fb9d3975695cf5f2aca2ffbb8396a9b55ba5c298 100644 (file)
@@ -5,8 +5,8 @@
 
 #include "fd-util.h"
 #include "fdset.h"
-#include "fileio.h"
 #include "macro.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void test_fdset_new_fill(void) {
index ac86d6d588f0287d3a8fa247165b5261388da3ba..44047f2e5a2f0d7c9ccaf15b9b14aea889f9a593 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "alloc-util.h"
 #include "ctype.h"
-#include "def.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -17,6 +17,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void test_parse_env_file(void) {
index 2527cacbbd117632799bc26248c8006b261c07a2..5bede5c75b4b04555b91bb5657cd9ea7ea3b04f0 100644 (file)
@@ -9,7 +9,7 @@ static void test_issue_9549(void) {
         _cleanup_(table_unrefp) Table *table = NULL;
         _cleanup_free_ char *formatted = NULL;
 
-        assert_se(table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED"));
+        assert_se(table = table_new("name", "type", "ro", "usage", "created", "modified"));
         assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(3), 100) >= 0);
         assert_se(table_add_many(table,
                                  TABLE_STRING, "foooo",
@@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(setenv("COLUMNS", "40", 1) >= 0);
 
-        assert_se(t = table_new("ONE", "TWO", "THREE"));
+        assert_se(t = table_new("one", "two", "three"));
 
         assert_se(table_set_align_percent(t, TABLE_HEADER_CELL(2), 100) >= 0);
 
index 26980d939f4736a55ec3f9435d531bcdfb3e8495..b3a4b1749c23157a7dcdf427f2ed65c2a852a2b1 100644 (file)
@@ -4,8 +4,6 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "id128-util.h"
 #include "macro.h"
@@ -16,6 +14,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 #include "virt.h"
index d78d6223c05f5b8443ca811cf67ae824ce3deaff..b4f41445fe22d65446e6be3e043f5f00607829d2 100644 (file)
@@ -7,11 +7,11 @@
 
 #include "alloc-util.h"
 #include "dirent-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "glob-util.h"
 #include "macro.h"
 #include "rm-rf.h"
+#include "tmpfile-util.h"
 
 static void test_glob_exists(void) {
         char name[] = "/tmp/test-glob_exists.XXXXXX";
index 82837da4f620d83d9b3af8ce33e371b26674054d..c04ef0b1f72f76b5a6d95ae01ae13b245df14192 100644 (file)
@@ -863,6 +863,43 @@ static void test_hashmap_clear_free_free(void) {
 
         hashmap_clear_free_free(m);
         assert_se(hashmap_isempty(m));
+
+        assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1);
+        assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1);
+        assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1);
+
+        hashmap_clear_free_free(m);
+        assert_se(hashmap_isempty(m));
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key, char, string_hash_func, string_compare_func, free);
+DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full, char, string_hash_func, string_compare_func, free, char, free);
+
+static void test_hashmap_clear_free_with_destructor(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+
+        log_info("%s", __func__);
+
+        m = hashmap_new(&test_hash_ops_key);
+        assert_se(m);
+
+        assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1);
+        assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1);
+        assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1);
+
+        hashmap_clear_free(m);
+        assert_se(hashmap_isempty(m));
+        m = hashmap_free(m);
+
+        m = hashmap_new(&test_hash_ops_full);
+        assert_se(m);
+
+        assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1);
+        assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1);
+        assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1);
+
+        hashmap_clear_free(m);
+        assert_se(hashmap_isempty(m));
 }
 
 static void test_hashmap_reserve(void) {
@@ -915,5 +952,6 @@ void test_hashmap_funcs(void) {
         test_hashmap_steal_first_key();
         test_hashmap_steal_first();
         test_hashmap_clear_free_free();
+        test_hashmap_clear_free_with_destructor();
         test_hashmap_reserve();
 }
index 194a640eee55218b8b50f34637475a0d46d23dca..4126a24ceb9fd10444e59a759c56b24309d7f781 100644 (file)
@@ -4,6 +4,7 @@
 #include "fileio.h"
 #include "hostname-util.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void test_hostname_is_valid(void) {
@@ -52,6 +53,12 @@ static void test_hostname_cleanup(void) {
         assert_se(streq(hostname_cleanup(s), "foobar.com"));
         s = strdupa("foobar.com.");
         assert_se(streq(hostname_cleanup(s), "foobar.com"));
+        s = strdupa("foo-bar.-com-.");
+        assert_se(streq(hostname_cleanup(s), "foo-bar.com"));
+        s = strdupa("foo-bar-.-com-.");
+        assert_se(streq(hostname_cleanup(s), "foo-bar--com"));
+        s = strdupa("--foo-bar.-com");
+        assert_se(streq(hostname_cleanup(s), "foo-bar.com"));
         s = strdupa("fooBAR");
         assert_se(streq(hostname_cleanup(s), "fooBAR"));
         s = strdupa("fooBAR.com");
@@ -78,6 +85,8 @@ static void test_hostname_cleanup(void) {
         assert_se(streq(hostname_cleanup(s), "foo.bar"));
         s = strdupa("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
         assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
+        s = strdupa("xxxx........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+        assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
 }
 
 static void test_read_etc_hostname(void) {
index e3d07a69f3c64d2f7db39df2db81a23c9e6be579..ec50e057a3655c38eed232a43409ce98302c259e 100644 (file)
@@ -7,10 +7,10 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "id128-util.h"
 #include "macro.h"
 #include "string-util.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10)
diff --git a/src/test/test-ip-protocol-list.c b/src/test/test-ip-protocol-list.c
new file mode 100644 (file)
index 0000000..79390e5
--- /dev/null
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <netinet/in.h>
+
+#include "macro.h"
+#include "ip-protocol-list.h"
+#include "stdio-util.h"
+#include "string-util.h"
+
+static void test_int(int i) {
+        char str[DECIMAL_STR_MAX(int)];
+
+        assert_se(ip_protocol_from_name(ip_protocol_to_name(i)) == i);
+
+        xsprintf(str, "%i", i);
+        assert_se(ip_protocol_from_name(ip_protocol_to_name(parse_ip_protocol(str))) == i);
+}
+
+static void test_int_fail(int i) {
+        char str[DECIMAL_STR_MAX(int)];
+
+        assert_se(!ip_protocol_to_name(i));
+
+        xsprintf(str, "%i", i);
+        assert_se(parse_ip_protocol(str) == -EINVAL);
+}
+
+static void test_str(const char *s) {
+        assert_se(streq(ip_protocol_to_name(ip_protocol_from_name(s)), s));
+        assert_se(streq(ip_protocol_to_name(parse_ip_protocol(s)), s));
+}
+
+static void test_str_fail(const char *s) {
+        assert_se(ip_protocol_from_name(s) == -EINVAL);
+        assert_se(parse_ip_protocol(s) == -EINVAL);
+}
+
+static void test_parse_ip_protocol(const char *s, int expected) {
+        assert_se(parse_ip_protocol(s) == expected);
+}
+
+int main(int argc, const char *argv[]) {
+        test_int(IPPROTO_TCP);
+        test_int(IPPROTO_DCCP);
+        test_int_fail(-1);
+        test_int_fail(1024 * 1024);
+
+        test_str("sctp");
+        test_str("udp");
+        test_str_fail("hoge");
+        test_str_fail("-1");
+        test_str_fail("1000000000");
+
+        test_parse_ip_protocol("sctp", IPPROTO_SCTP);
+        test_parse_ip_protocol("ScTp", IPPROTO_SCTP);
+        test_parse_ip_protocol("ip", IPPROTO_IP);
+        test_parse_ip_protocol("", IPPROTO_IP);
+        test_parse_ip_protocol("1", 1);
+        test_parse_ip_protocol("0", 0);
+        test_parse_ip_protocol("-10", -EINVAL);
+        test_parse_ip_protocol("100000000", -EINVAL);
+
+        return 0;
+}
index dc5f9eae8370b4beb3e1aa2930f43b5974e196c5..d51e0d94fd36a1438e72e5f271ba4e63653b8aff 100644 (file)
@@ -6,7 +6,7 @@
 #include "service.h"
 #include "unit.h"
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
         JobType a, b, c, ab, bc, ab_c, bc_a, a_bc;
         const ServiceState test_states[] = { SERVICE_DEAD, SERVICE_RUNNING };
         unsigned i;
index c1ceb0bbd8b47e645a0c3112127dd6a07c0c0b39..cddbfa7022416b65c21eb60d2d27ae5ec7ac8c63 100644 (file)
@@ -25,7 +25,7 @@ static void test_basic_parsing(void) {
         _cleanup_free_ char *journal_data_path = NULL;
         int r;
 
-        journal_data_path = path_join(NULL, get_testdata_dir(), "journal-data/journal-1.txt");
+        journal_data_path = path_join(get_testdata_dir(), "journal-data/journal-1.txt");
         imp.fd = open(journal_data_path, O_RDONLY|O_CLOEXEC);
         assert_se(imp.fd >= 0);
 
@@ -56,7 +56,7 @@ static void test_bad_input(void) {
         _cleanup_free_ char *journal_data_path = NULL;
         int r;
 
-        journal_data_path = path_join(NULL, get_testdata_dir(), "journal-data/journal-2.txt");
+        journal_data_path = path_join(get_testdata_dir(), "journal-data/journal-2.txt");
         imp.fd = open(journal_data_path, O_RDONLY|O_CLOEXEC);
         assert_se(imp.fd >= 0);
 
index a1d4307eb51feff7d54d1fbce899de31ad1c5a17..48994547ac3be3ea9347d9ce3f227cfbb6a9cbc3 100644 (file)
@@ -65,7 +65,7 @@ static void test_keymaps(void) {
 
 #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
 static void dump_special_glyphs(void) {
-        assert_cc(CROSS_MARK + 1 == _SPECIAL_GLYPH_MAX);
+        assert_cc(DEPRESSED_SMILEY + 1 == _SPECIAL_GLYPH_MAX);
 
         log_info("/* %s */", __func__);
 
@@ -84,6 +84,13 @@ static void dump_special_glyphs(void) {
         dump_glyph(MU);
         dump_glyph(CHECK_MARK);
         dump_glyph(CROSS_MARK);
+        dump_glyph(ECSTATIC_SMILEY);
+        dump_glyph(HAPPY_SMILEY);
+        dump_glyph(SLIGHTLY_HAPPY_SMILEY);
+        dump_glyph(NEUTRAL_SMILEY);
+        dump_glyph(SLIGHTLY_UNHAPPY_SMILEY);
+        dump_glyph(UNHAPPY_SMILEY);
+        dump_glyph(DEPRESSED_SMILEY);
 }
 
 int main(int argc, char *argv[]) {
index 56e385aa11703bb886bd3fb63c26ba1683edbc84..6986405dc6c89f685195f2c5ca54185bc76d9ddd 100644 (file)
 #include <sys/mount.h>
 
 #include "alloc-util.h"
-#include "def.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "log.h"
-#include "log.h"
 #include "mount-util.h"
-#include "path-util.h"
-#include "rm-rf.h"
 #include "string-util.h"
 #include "tests.h"
 
-static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
-        long unsigned flags;
-
-        assert_se(mount_propagation_flags_from_string(name, &flags) == ret);
-
-        if (ret >= 0) {
-                const char *c;
-
-                assert_se(flags == expected);
-
-                c = mount_propagation_flags_to_string(flags);
-                if (isempty(name))
-                        assert_se(isempty(c));
-                else
-                        assert_se(streq(c, name));
-        }
-}
-
-static void test_mnt_id(void) {
-        _cleanup_fclose_ FILE *f = NULL;
-        Hashmap *h;
-        Iterator i;
-        char *p;
-        void *k;
-        int r;
-
-        assert_se(f = fopen("/proc/self/mountinfo", "re"));
-        assert_se(h = hashmap_new(&trivial_hash_ops));
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL, *path = NULL;
-                int mnt_id;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r == 0)
-                        break;
-                assert_se(r > 0);
-
-                assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
-
-                assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0);
-                path = NULL;
-        }
-
-        HASHMAP_FOREACH_KEY(p, k, h, i) {
-                int mnt_id = PTR_TO_INT(k), mnt_id2;
-
-                r = path_get_mnt_id(p, &mnt_id2);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p);
-                        continue;
-                }
-
-                log_debug("mnt id of %s is %i\n", p, mnt_id2);
-
-                if (mnt_id == mnt_id2)
-                        continue;
-
-                /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
-                 * the case */
-                assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p));
-        }
-
-        hashmap_free_free(h);
-}
-
-static void test_path_is_mount_point(void) {
-        int fd;
-        char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
-        _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
-        _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
-        _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
-
-        assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/", NULL, 0) > 0);
-        assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("//", NULL, 0) > 0);
-
-        assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
-        assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
-
-        assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
-        assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
-
-        assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
-        assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
-
-        /* we'll create a hierarchy of different kinds of dir/file/link
-         * layouts:
-         *
-         * <tmp>/file1, <tmp>/file2
-         * <tmp>/link1 -> file1, <tmp>/link2 -> file2
-         * <tmp>/dir1/
-         * <tmp>/dir1/file
-         * <tmp>/dirlink1 -> dir1
-         * <tmp>/dirlink1file -> dirlink1/file
-         * <tmp>/dir2/
-         * <tmp>/dir2/file
-         */
-
-        /* file mountpoints */
-        assert_se(mkdtemp(tmp_dir) != NULL);
-        file1 = path_join(NULL, tmp_dir, "file1");
-        assert_se(file1);
-        file2 = path_join(NULL, tmp_dir, "file2");
-        assert_se(file2);
-        fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-        fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-        link1 = path_join(NULL, tmp_dir, "link1");
-        assert_se(link1);
-        assert_se(symlink("file1", link1) == 0);
-        link2 = path_join(NULL, tmp_dir, "link2");
-        assert_se(link1);
-        assert_se(symlink("file2", link2) == 0);
-
-        assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(file1, NULL, 0) == 0);
-        assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(link1, NULL, 0) == 0);
-
-        /* directory mountpoints */
-        dir1 = path_join(NULL, tmp_dir, "dir1");
-        assert_se(dir1);
-        assert_se(mkdir(dir1, 0755) == 0);
-        dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
-        assert_se(dirlink1);
-        assert_se(symlink("dir1", dirlink1) == 0);
-        dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
-        assert_se(dirlink1file);
-        assert_se(symlink("dirlink1/file", dirlink1file) == 0);
-        dir2 = path_join(NULL, tmp_dir, "dir2");
-        assert_se(dir2);
-        assert_se(mkdir(dir2, 0755) == 0);
-
-        assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
-        assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
-
-        /* file in subdirectory mountpoints */
-        dir1file = path_join(NULL, dir1, "file");
-        assert_se(dir1file);
-        fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-
-        assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
-        assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
-
-        /* these tests will only work as root */
-        if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
-                int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
-                const char *file2d;
-
-                /* files */
-                /* capture results in vars, to avoid dangling mounts on failure */
-                log_info("%s: %s", __func__, file2);
-                rf = path_is_mount_point(file2, NULL, 0);
-                rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
-
-                file2d = strjoina(file2, "/");
-                log_info("%s: %s", __func__, file2d);
-                rdf = path_is_mount_point(file2d, NULL, 0);
-                rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
-
-                log_info("%s: %s", __func__, link2);
-                rlf = path_is_mount_point(link2, NULL, 0);
-                rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
-
-                assert_se(umount(file2) == 0);
-
-                assert_se(rf == 1);
-                assert_se(rt == 1);
-                assert_se(rdf == -ENOTDIR);
-                assert_se(rdt == -ENOTDIR);
-                assert_se(rlf == 0);
-                assert_se(rlt == 1);
-
-                /* dirs */
-                dir2file = path_join(NULL, dir2, "file");
-                assert_se(dir2file);
-                fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-                assert_se(fd > 0);
-                close(fd);
-
-                assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
-
-                log_info("%s: %s", __func__, dir1);
-                rf = path_is_mount_point(dir1, NULL, 0);
-                rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
-                log_info("%s: %s", __func__, dirlink1);
-                rlf = path_is_mount_point(dirlink1, NULL, 0);
-                rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
-                log_info("%s: %s", __func__, dirlink1file);
-                /* its parent is a mount point, but not /file itself */
-                rl1f = path_is_mount_point(dirlink1file, NULL, 0);
-                rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
-
-                assert_se(umount(dir1) == 0);
-
-                assert_se(rf == 1);
-                assert_se(rt == 1);
-                assert_se(rlf == 0);
-                assert_se(rlt == 1);
-                assert_se(rl1f == 0);
-                assert_se(rl1t == 0);
-
-        } else
-                printf("Skipping bind mount file test: %m\n");
-
-        assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
-}
-
 static void test_mount_option_mangle(void) {
         char *opts = NULL;
         unsigned long f;
@@ -295,19 +62,8 @@ static void test_mount_option_mangle(void) {
 }
 
 int main(int argc, char *argv[]) {
-
         test_setup_logging(LOG_DEBUG);
 
-        test_mount_propagation_flags("shared", 0, MS_SHARED);
-        test_mount_propagation_flags("slave", 0, MS_SLAVE);
-        test_mount_propagation_flags("private", 0, MS_PRIVATE);
-        test_mount_propagation_flags(NULL, 0, 0);
-        test_mount_propagation_flags("", 0, 0);
-        test_mount_propagation_flags("xxxx", -EINVAL, 0);
-        test_mount_propagation_flags(" ", -EINVAL, 0);
-
-        test_mnt_id();
-        test_path_is_mount_point();
         test_mount_option_mangle();
 
         return 0;
diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
new file mode 100644 (file)
index 0000000..767a9fb
--- /dev/null
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/mount.h>
+
+#include "alloc-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "log.h"
+#include "log.h"
+#include "mountpoint-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "tests.h"
+
+static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
+        long unsigned flags;
+
+        assert_se(mount_propagation_flags_from_string(name, &flags) == ret);
+
+        if (ret >= 0) {
+                const char *c;
+
+                assert_se(flags == expected);
+
+                c = mount_propagation_flags_to_string(flags);
+                if (isempty(name))
+                        assert_se(isempty(c));
+                else
+                        assert_se(streq(c, name));
+        }
+}
+
+static void test_mnt_id(void) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Hashmap *h;
+        Iterator i;
+        char *p;
+        void *k;
+        int r;
+
+        assert_se(f = fopen("/proc/self/mountinfo", "re"));
+        assert_se(h = hashmap_new(&trivial_hash_ops));
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL, *path = NULL;
+                int mnt_id;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r == 0)
+                        break;
+                assert_se(r > 0);
+
+                assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
+
+                assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0);
+                path = NULL;
+        }
+
+        HASHMAP_FOREACH_KEY(p, k, h, i) {
+                int mnt_id = PTR_TO_INT(k), mnt_id2;
+
+                r = path_get_mnt_id(p, &mnt_id2);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p);
+                        continue;
+                }
+
+                log_debug("mnt id of %s is %i\n", p, mnt_id2);
+
+                if (mnt_id == mnt_id2)
+                        continue;
+
+                /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
+                 * the case */
+                assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p));
+        }
+
+        hashmap_free_free(h);
+}
+
+static void test_path_is_mount_point(void) {
+        int fd;
+        char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
+        _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
+        _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
+        _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
+
+        assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/", NULL, 0) > 0);
+        assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("//", NULL, 0) > 0);
+
+        assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
+        assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
+
+        assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
+        assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
+
+        assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
+        assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
+
+        /* we'll create a hierarchy of different kinds of dir/file/link
+         * layouts:
+         *
+         * <tmp>/file1, <tmp>/file2
+         * <tmp>/link1 -> file1, <tmp>/link2 -> file2
+         * <tmp>/dir1/
+         * <tmp>/dir1/file
+         * <tmp>/dirlink1 -> dir1
+         * <tmp>/dirlink1file -> dirlink1/file
+         * <tmp>/dir2/
+         * <tmp>/dir2/file
+         */
+
+        /* file mountpoints */
+        assert_se(mkdtemp(tmp_dir) != NULL);
+        file1 = path_join(tmp_dir, "file1");
+        assert_se(file1);
+        file2 = path_join(tmp_dir, "file2");
+        assert_se(file2);
+        fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+        fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+        link1 = path_join(tmp_dir, "link1");
+        assert_se(link1);
+        assert_se(symlink("file1", link1) == 0);
+        link2 = path_join(tmp_dir, "link2");
+        assert_se(link1);
+        assert_se(symlink("file2", link2) == 0);
+
+        assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(file1, NULL, 0) == 0);
+        assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(link1, NULL, 0) == 0);
+
+        /* directory mountpoints */
+        dir1 = path_join(tmp_dir, "dir1");
+        assert_se(dir1);
+        assert_se(mkdir(dir1, 0755) == 0);
+        dirlink1 = path_join(tmp_dir, "dirlink1");
+        assert_se(dirlink1);
+        assert_se(symlink("dir1", dirlink1) == 0);
+        dirlink1file = path_join(tmp_dir, "dirlink1file");
+        assert_se(dirlink1file);
+        assert_se(symlink("dirlink1/file", dirlink1file) == 0);
+        dir2 = path_join(tmp_dir, "dir2");
+        assert_se(dir2);
+        assert_se(mkdir(dir2, 0755) == 0);
+
+        assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
+        assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
+
+        /* file in subdirectory mountpoints */
+        dir1file = path_join(dir1, "file");
+        assert_se(dir1file);
+        fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+
+        assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
+        assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
+
+        /* these tests will only work as root */
+        if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
+                int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
+                const char *file2d;
+
+                /* files */
+                /* capture results in vars, to avoid dangling mounts on failure */
+                log_info("%s: %s", __func__, file2);
+                rf = path_is_mount_point(file2, NULL, 0);
+                rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
+
+                file2d = strjoina(file2, "/");
+                log_info("%s: %s", __func__, file2d);
+                rdf = path_is_mount_point(file2d, NULL, 0);
+                rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
+
+                log_info("%s: %s", __func__, link2);
+                rlf = path_is_mount_point(link2, NULL, 0);
+                rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
+
+                assert_se(umount(file2) == 0);
+
+                assert_se(rf == 1);
+                assert_se(rt == 1);
+                assert_se(rdf == -ENOTDIR);
+                assert_se(rdt == -ENOTDIR);
+                assert_se(rlf == 0);
+                assert_se(rlt == 1);
+
+                /* dirs */
+                dir2file = path_join(dir2, "file");
+                assert_se(dir2file);
+                fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+                assert_se(fd > 0);
+                close(fd);
+
+                assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
+
+                log_info("%s: %s", __func__, dir1);
+                rf = path_is_mount_point(dir1, NULL, 0);
+                rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
+                log_info("%s: %s", __func__, dirlink1);
+                rlf = path_is_mount_point(dirlink1, NULL, 0);
+                rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
+                log_info("%s: %s", __func__, dirlink1file);
+                /* its parent is a mount point, but not /file itself */
+                rl1f = path_is_mount_point(dirlink1file, NULL, 0);
+                rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
+
+                assert_se(umount(dir1) == 0);
+
+                assert_se(rf == 1);
+                assert_se(rt == 1);
+                assert_se(rlf == 0);
+                assert_se(rlt == 1);
+                assert_se(rl1f == 0);
+                assert_se(rl1t == 0);
+
+        } else
+                printf("Skipping bind mount file test: %m\n");
+
+        assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_DEBUG);
+
+        test_mount_propagation_flags("shared", 0, MS_SHARED);
+        test_mount_propagation_flags("slave", 0, MS_SLAVE);
+        test_mount_propagation_flags("private", 0, MS_PRIVATE);
+        test_mount_propagation_flags(NULL, 0, 0);
+        test_mount_propagation_flags("", 0, 0);
+        test_mount_propagation_flags("xxxx", -EINVAL, 0);
+        test_mount_propagation_flags(" ", -EINVAL, 0);
+
+        test_mnt_id();
+        test_path_is_mount_point();
+
+        return 0;
+}
index e9aef5e88269e7903f46a0c7693fcd948a1381ed..d732f402f0b9091769cc3a3666b0ea442f433c92 100644 (file)
@@ -726,10 +726,12 @@ static void test_parse_dev(void) {
         assert_se(parse_dev("5", &dev) == -EINVAL);
         assert_se(parse_dev("5:", &dev) == -EINVAL);
         assert_se(parse_dev(":5", &dev) == -EINVAL);
+        assert_se(parse_dev("-1:-1", &dev) == -EINVAL);
 #if SIZEOF_DEV_T < 8
         assert_se(parse_dev("4294967295:4294967295", &dev) == -EINVAL);
 #endif
         assert_se(parse_dev("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11);
+        assert_se(parse_dev("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0);
 }
 
 static void test_parse_errno(void) {
index b5030ea494a081f6c005f702b91b16080fc85421..8854a94f6ccc730709ebc8e35fa2933de230750a 100644 (file)
@@ -6,7 +6,7 @@
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stat-util.h"
@@ -232,23 +232,47 @@ static void test_prefixes(void) {
 
 static void test_path_join(void) {
 
-#define test_join(root, path, rest, expected) {  \
+#define test_join(expected, ...) {        \
                 _cleanup_free_ char *z = NULL;   \
-                z = path_join(root, path, rest); \
+                z = path_join(__VA_ARGS__); \
+                log_debug("got \"%s\", expected \"%s\"", z, expected); \
                 assert_se(streq(z, expected));   \
         }
 
-        test_join("/root", "/a/b", "/c", "/root/a/b/c");
-        test_join("/root", "a/b", "c", "/root/a/b/c");
-        test_join("/root", "/a/b", "c", "/root/a/b/c");
-        test_join("/root", "/", "c", "/root/c");
-        test_join("/root", "/", NULL, "/root/");
-
-        test_join(NULL, "/a/b", "/c", "/a/b/c");
-        test_join(NULL, "a/b", "c", "a/b/c");
-        test_join(NULL, "/a/b", "c", "/a/b/c");
-        test_join(NULL, "/", "c", "/c");
-        test_join(NULL, "/", NULL, "/");
+        test_join("/root/a/b/c", "/root", "/a/b", "/c");
+        test_join("/root/a/b/c", "/root", "a/b", "c");
+        test_join("/root/a/b/c", "/root", "/a/b", "c");
+        test_join("/root/c",     "/root", "/", "c");
+        test_join("/root/",      "/root", "/", NULL);
+
+        test_join("/a/b/c", "", "/a/b", "/c");
+        test_join("a/b/c",  "", "a/b", "c");
+        test_join("/a/b/c", "", "/a/b", "c");
+        test_join("/c",     "", "/", "c");
+        test_join("/",      "", "/", NULL);
+
+        test_join("/a/b/c", NULL, "/a/b", "/c");
+        test_join("a/b/c",  NULL, "a/b", "c");
+        test_join("/a/b/c", NULL, "/a/b", "c");
+        test_join("/c",     NULL, "/", "c");
+        test_join("/",      NULL, "/", NULL);
+
+        test_join("", "", NULL);
+        test_join("", NULL, "");
+        test_join("", NULL, NULL);
+
+        test_join("foo/bar", "foo", "bar");
+        test_join("foo/bar", "", "foo", "bar");
+        test_join("foo/bar", NULL, "foo", NULL, "bar");
+        test_join("foo/bar", "", "foo", "", "bar", "");
+        test_join("foo/bar", "", "", "", "", "foo", "", "", "", "bar", "", "", "");
+
+        test_join("//foo///bar//",         "", "/", "", "/foo/", "", "/", "", "/bar/", "", "/", "");
+        test_join("/foo/bar/",             "/", "foo", "/", "bar", "/");
+        test_join("foo/bar/baz",           "foo", "bar", "baz");
+        test_join("foo/bar/baz",           "foo/", "bar", "/baz");
+        test_join("foo//bar//baz",         "foo/", "/bar/", "/baz");
+        test_join("//foo////bar////baz//", "//foo/", "///bar/", "///baz//");
 }
 
 static void test_fsck_exists(void) {
@@ -406,6 +430,7 @@ static void test_file_in_same_dir(void) {
 }
 
 static void test_last_path_component(void) {
+        assert_se(last_path_component(NULL) == NULL);
         assert_se(streq(last_path_component("a/b/c"), "c"));
         assert_se(streq(last_path_component("a/b/c/"), "c/"));
         assert_se(streq(last_path_component("/"), "/"));
@@ -424,6 +449,45 @@ static void test_last_path_component(void) {
         assert_se(streq(last_path_component("/a/"), "a/"));
 }
 
+static void test_path_extract_filename_one(const char *input, const char *output, int ret) {
+        _cleanup_free_ char *k = NULL;
+        int r;
+
+        r = path_extract_filename(input, &k);
+        log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror(-r), strnull(output), strerror(-ret));
+        assert_se(streq_ptr(k, output));
+        assert_se(r == ret);
+}
+
+static void test_path_extract_filename(void) {
+        test_path_extract_filename_one(NULL, NULL, -EINVAL);
+        test_path_extract_filename_one("a/b/c", "c", 0);
+        test_path_extract_filename_one("a/b/c/", "c", 0);
+        test_path_extract_filename_one("/", NULL, -EINVAL);
+        test_path_extract_filename_one("//", NULL, -EINVAL);
+        test_path_extract_filename_one("///", NULL, -EINVAL);
+        test_path_extract_filename_one(".", NULL, -EINVAL);
+        test_path_extract_filename_one("./.", NULL, -EINVAL);
+        test_path_extract_filename_one("././", NULL, -EINVAL);
+        test_path_extract_filename_one("././/", NULL, -EINVAL);
+        test_path_extract_filename_one("/foo/a", "a", 0);
+        test_path_extract_filename_one("/foo/a/", "a", 0);
+        test_path_extract_filename_one("", NULL, -EINVAL);
+        test_path_extract_filename_one("a", "a", 0);
+        test_path_extract_filename_one("a/", "a", 0);
+        test_path_extract_filename_one("/a", "a", 0);
+        test_path_extract_filename_one("/a/", "a", 0);
+        test_path_extract_filename_one("/////////////a/////////////", "a", 0);
+        test_path_extract_filename_one("xx/.", NULL, -EINVAL);
+        test_path_extract_filename_one("xx/..", NULL, -EINVAL);
+        test_path_extract_filename_one("..", NULL, -EINVAL);
+        test_path_extract_filename_one("/..", NULL, -EINVAL);
+        test_path_extract_filename_one("../", NULL, -EINVAL);
+        test_path_extract_filename_one(".", NULL, -EINVAL);
+        test_path_extract_filename_one("/.", NULL, -EINVAL);
+        test_path_extract_filename_one("./", NULL, -EINVAL);
+}
+
 static void test_filename_is_valid(void) {
         char foo[FILENAME_MAX+2];
         int i;
@@ -542,6 +606,7 @@ int main(int argc, char **argv) {
         test_prefix_root();
         test_file_in_same_dir();
         test_last_path_component();
+        test_path_extract_filename();
         test_filename_is_valid();
         test_hidden_or_backup_file();
         test_skip_dev_prefix();
index edc0479522aff656427158bd3d9212e7e77e4b52..07a0e413ee357db9e9e204ceac796e40172282a4 100644 (file)
@@ -252,7 +252,7 @@ int main(int argc, char *argv[]) {
 
         test_setup_logging(LOG_INFO);
 
-        test_path = path_join(NULL, get_testdata_dir(), "test-path");
+        test_path = path_join(get_testdata_dir(), "test-path");
         assert_se(set_unit_path(test_path) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
index a93d37d46029d8c349d9d43930c66a795ff79de9..bc5fdd15b269b19afe958705d3ce86587f6abe6c 100644 (file)
@@ -48,22 +48,15 @@ struct test {
         unsigned idx;
 };
 
-static int test_compare(const void *a, const void *b) {
-        const struct test *x = a, *y = b;
-
+static int test_compare(const struct test *x, const struct test *y) {
         return CMP(x->value, y->value);
 }
 
-static void test_hash(const void *a, struct siphash *state) {
-        const struct test *x = a;
-
+static void test_hash(const struct test *x, struct siphash *state) {
         siphash24_compress(&x->value, sizeof(x->value), state);
 }
 
-static const struct hash_ops test_hash_ops = {
-        .hash = test_hash,
-        .compare = test_compare
-};
+DEFINE_PRIVATE_HASH_OPS(test_hash_ops, struct test, test_hash, test_compare);
 
 static void test_struct(void) {
         _cleanup_(prioq_freep) Prioq *q = NULL;
@@ -73,7 +66,7 @@ static void test_struct(void) {
 
         srand(0);
 
-        assert_se(q = prioq_new(test_compare));
+        assert_se(q = prioq_new((compare_func_t) test_compare));
         assert_se(s = set_new(&test_hash_ops));
 
         for (i = 0; i < SET_SIZE; i++) {
index ae0f1a564d72747fbe343a3de6df3093a3687add..5c87db08f56302a8b4d04abd7a8eb8cb6fff973d 100644 (file)
@@ -17,6 +17,7 @@
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "signal-util.h"
index 15701b2712d1484cf3498951e549adc17e3bef29..771719a26753fdf725a4ec55ffe14f1fe8de700a 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "capability-util.h"
 #include "macro.h"
+#include "missing.h"
 #include "rlimit-util.h"
 #include "string-util.h"
 #include "util.h"
index e306b1f1d63782a6a830d98ac5de8b8d4f960cd1..a57d5db2b10c4242082f3a24bf906731d9192c7f 100644 (file)
@@ -8,6 +8,7 @@
 #include "serialize.h"
 #include "strv.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 
 char long_string[LONG_LINE_MAX+1];
 
index 6307403e4c05b74b535710b604572b5a7111876b..340edeb65f605c442793463eb2ce1d4c457f5b90 100644 (file)
@@ -45,6 +45,24 @@ static void test_set_free_with_destructor(void) {
         assert_se(items[3].seen == 0);
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_hash_ops, void, trivial_hash_func, trivial_compare_func, Item, item_seen);
+
+static void test_set_free_with_hash_ops(void) {
+        Set *m;
+        struct Item items[4] = {};
+        unsigned i;
+
+        assert_se(m = set_new(&item_hash_ops));
+        for (i = 0; i < ELEMENTSOF(items) - 1; i++)
+                assert_se(set_put(m, items + i) == 1);
+
+        m = set_free(m);
+        assert_se(items[0].seen == 1);
+        assert_se(items[1].seen == 1);
+        assert_se(items[2].seen == 1);
+        assert_se(items[3].seen == 0);
+}
+
 static void test_set_put(void) {
         _cleanup_set_free_ Set *m = NULL;
 
@@ -64,6 +82,7 @@ static void test_set_put(void) {
 int main(int argc, const char *argv[]) {
         test_set_steal_first();
         test_set_free_with_destructor();
+        test_set_free_with_hash_ops();
         test_set_put();
 
         return 0;
index 33c9d42e9e3711a3c7c1353dcca862a3d39eb8ce..d2666dd1d8ebe5d8f8a29e19c85ee538056331ff 100644 (file)
@@ -19,7 +19,7 @@ int main(int argc, char *argv[]) {
 
         test_setup_logging(LOG_INFO);
 
-#ifdef __SANITIZE_ADDRESS__
+#if HAS_FEATURE_ADDRESS_SANITIZER
         return log_tests_skipped("address-sanitizer is enabled");
 #endif
 #if HAVE_VALGRIND_VALGRIND_H
index 0de29c22350c86b0230174a493aaa135af8c47d6..07ff4878340f057d8dfd10733e4f4613b67ffd42 100644 (file)
@@ -6,20 +6,24 @@
 
 #include "alloc-util.h"
 #include "async.h"
+#include "escape.h"
 #include "exit-status.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "in-addr-util.h"
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing_network.h"
 #include "process-util.h"
 #include "socket-util.h"
 #include "string-util.h"
-#include "util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
+#include "util.h"
 
 static void test_ifname_valid(void) {
+        log_info("/* %s */", __func__);
+
         assert(ifname_valid("foo"));
         assert(ifname_valid("eth0"));
 
@@ -42,61 +46,121 @@ static void test_ifname_valid(void) {
         assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
 }
 
-static void test_socket_address_parse(void) {
+static void test_socket_address_parse_one(const char *in, int ret, int family, const char *expected) {
         SocketAddress a;
+        _cleanup_free_ char *out = NULL;
+        int r;
+
+        r = socket_address_parse(&a, in);
+        if (r >= 0)
+                assert_se(socket_address_print(&a, &out) >= 0);
+
+        log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in,
+                 r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-");
+        assert_se(r == ret);
+        if (r >= 0) {
+                assert_se(a.sockaddr.sa.sa_family == family);
+                assert_se(streq(out, expected ?: in));
+        }
+}
+
+#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path))
+assert_cc(sizeof(((struct sockaddr_un){}).sun_path) == 108);
+
+static void test_socket_address_parse(void) {
+        log_info("/* %s */", __func__);
 
-        assert_se(socket_address_parse(&a, "junk") < 0);
-        assert_se(socket_address_parse(&a, "192.168.1.1") < 0);
-        assert_se(socket_address_parse(&a, ".168.1.1") < 0);
-        assert_se(socket_address_parse(&a, "989.168.1.1") < 0);
-        assert_se(socket_address_parse(&a, "192.168.1.1:65536") < 0);
-        assert_se(socket_address_parse(&a, "192.168.1.1:0") < 0);
-        assert_se(socket_address_parse(&a, "0") < 0);
-        assert_se(socket_address_parse(&a, "65536") < 0);
+        test_socket_address_parse_one("junk", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("192.168.1.1", -EINVAL, 0, NULL);
+        test_socket_address_parse_one(".168.1.1", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("989.168.1.1", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("192.168.1.1:65536", -ERANGE, 0, NULL);
+        test_socket_address_parse_one("192.168.1.1:0", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("0", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("65536", -ERANGE, 0, NULL);
 
-        assert_se(socket_address_parse(&a, "65535") >= 0);
+        const int default_family = socket_ipv6_is_supported() ? AF_INET6 : AF_INET;
+
+        test_socket_address_parse_one("65535", 0, default_family, "[::]:65535");
 
         /* The checks below will pass even if ipv6 is disabled in
          * kernel. The underlying glibc's inet_pton() is just a string
          * parser and doesn't make any syscalls. */
 
-        assert_se(socket_address_parse(&a, "[::1]") < 0);
-        assert_se(socket_address_parse(&a, "[::1]8888") < 0);
-        assert_se(socket_address_parse(&a, "::1") < 0);
-        assert_se(socket_address_parse(&a, "[::1]:0") < 0);
-        assert_se(socket_address_parse(&a, "[::1]:65536") < 0);
-        assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0);
+        test_socket_address_parse_one("[::1]", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("[::1]8888", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("::1", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL);
+        test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL);
 
-        assert_se(socket_address_parse(&a, "8888") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET));
+        test_socket_address_parse_one("8888", 0, default_family, "[::]:8888");
+        test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
+                                      "[2001:db8:0:85a3::ac1f:8001]:8888");
+        test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL);
+        test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL);
+        test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL);
+        test_socket_address_parse_one("/", 0, AF_UNIX, NULL);
+        test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL);
 
-        assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_INET6);
+        {
+                char aaa[SUN_PATH_LEN + 1] = "@";
 
-        assert_se(socket_address_parse(&a, "[::1]:8888") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_INET6);
+                memset(aaa + 1, 'a', SUN_PATH_LEN - 1);
+                char_array_0(aaa);
 
-        assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_INET);
+                test_socket_address_parse_one(aaa, -EINVAL, 0, NULL);
 
-        assert_se(socket_address_parse(&a, "/foo/bar") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_UNIX);
+                aaa[SUN_PATH_LEN - 1] = '\0';
+                test_socket_address_parse_one(aaa, 0, AF_UNIX, NULL);
+        }
 
-        assert_se(socket_address_parse(&a, "@abstract") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_UNIX);
+        test_socket_address_parse_one("vsock:2:1234", 0, AF_VSOCK, NULL);
+        test_socket_address_parse_one("vsock::1234", 0, AF_VSOCK, NULL);
+        test_socket_address_parse_one("vsock:2:1234x", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("vsock:2x:1234", -EINVAL, 0, NULL);
+        test_socket_address_parse_one("vsock:2", -EINVAL, 0, NULL);
+}
 
-        assert_se(socket_address_parse(&a, "vsock::1234") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_VSOCK);
-        assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_VSOCK);
-        assert_se(socket_address_parse(&a, "vsock:2:1234x") < 0);
-        assert_se(socket_address_parse(&a, "vsock:2x:1234") < 0);
-        assert_se(socket_address_parse(&a, "vsock:2") < 0);
+static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) {
+        _cleanup_free_ char *out = NULL, *c = NULL;
+
+        SocketAddress a = { .sockaddr = { .un = { .sun_family = AF_UNIX } },
+                            .size = offsetof(struct sockaddr_un, sun_path) + len_in,
+                            .type = SOCK_STREAM,
+        };
+        memcpy(a.sockaddr.un.sun_path, in, len_in);
+
+        assert_se(socket_address_print(&a, &out) >= 0);
+        assert_se(c = cescape(in));
+        log_info("\"%s\" → \"%s\" (expect \"%s\")", in, out, expected);
+        assert_se(streq(out, expected));
+}
+
+static void test_socket_print_unix(void) {
+        log_info("/* %s */", __func__);
+
+        /* Some additional tests for abstract addresses which we don't parse */
+
+        test_socket_print_unix_one("\0\0\0\0", 4, "@\\000\\000\\000");
+        test_socket_print_unix_one("@abs", 5, "@abs");
+        test_socket_print_unix_one("\n", 2, "\\n");
+        test_socket_print_unix_one("", 1, "<unnamed>");
+        test_socket_print_unix_one("\0", 1, "<unnamed>");
+        test_socket_print_unix_one("\0_________________________there's 108 characters in this string_____________________________________________", 108,
+                                   "@_________________________there\\'s 108 characters in this string_____________________________________________");
+        test_socket_print_unix_one("////////////////////////////////////////////////////////////////////////////////////////////////////////////", 108,
+                                   "////////////////////////////////////////////////////////////////////////////////////////////////////////////");
+        test_socket_print_unix_one("////////////////////////////////////////////////////////////////////////////////////////////////////////////", 109,
+                                   "////////////////////////////////////////////////////////////////////////////////////////////////////////////");
+        test_socket_print_unix_one("\0\a\b\n\255", 6, "@\\a\\b\\n\\255\\000");
 }
 
 static void test_socket_address_parse_netlink(void) {
         SocketAddress a;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socket_address_parse_netlink(&a, "junk") < 0);
         assert_se(socket_address_parse_netlink(&a, "") < 0);
 
@@ -120,8 +184,9 @@ static void test_socket_address_parse_netlink(void) {
 }
 
 static void test_socket_address_equal(void) {
-        SocketAddress a;
-        SocketAddress b;
+        SocketAddress a, b;
+
+        log_info("/* %s */", __func__);
 
         assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
         assert_se(socket_address_parse(&b, "192.168.1.1:888") >= 0);
@@ -171,6 +236,8 @@ static void test_socket_address_equal(void) {
 static void test_socket_address_get_path(void) {
         SocketAddress a;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
         assert_se(!socket_address_get_path(&a));
 
@@ -190,6 +257,8 @@ static void test_socket_address_get_path(void) {
 static void test_socket_address_is(void) {
         SocketAddress a;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
         assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
         assert_se(!socket_address_is(&a, "route", SOCK_STREAM));
@@ -199,6 +268,8 @@ static void test_socket_address_is(void) {
 static void test_socket_address_is_netlink(void) {
         SocketAddress a;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socket_address_parse_netlink(&a, "route 10") >= 0);
         assert_se(socket_address_is_netlink(&a, "route 10"));
         assert_se(!socket_address_is_netlink(&a, "192.168.1.1:8888"));
@@ -206,9 +277,10 @@ static void test_socket_address_is_netlink(void) {
 }
 
 static void test_in_addr_is_null(void) {
-
         union in_addr_union i = {};
 
+        log_info("/* %s */", __func__);
+
         assert_se(in_addr_is_null(AF_INET, &i) == true);
         assert_se(in_addr_is_null(AF_INET6, &i) == true);
 
@@ -229,6 +301,7 @@ static void test_in_addr_prefix_intersect_one(unsigned f, const char *a, unsigne
 }
 
 static void test_in_addr_prefix_intersect(void) {
+        log_info("/* %s */", __func__);
 
         test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 32, "255.255.255.254", 32, 0);
         test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 0, "255.255.255.255", 32, 1);
@@ -270,6 +343,7 @@ static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigne
 }
 
 static void test_in_addr_prefix_next(void) {
+        log_info("/* %s */", __func__);
 
         test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0");
         test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0");
@@ -289,7 +363,6 @@ static void test_in_addr_prefix_next(void) {
 
         test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, NULL);
         test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120, NULL);
-
 }
 
 static void test_in_addr_to_string_one(int f, const char *addr) {
@@ -303,6 +376,8 @@ static void test_in_addr_to_string_one(int f, const char *addr) {
 }
 
 static void test_in_addr_to_string(void) {
+        log_info("/* %s */", __func__);
+
         test_in_addr_to_string_one(AF_INET, "192.168.0.1");
         test_in_addr_to_string_one(AF_INET, "10.11.12.13");
         test_in_addr_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
@@ -327,6 +402,8 @@ static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex
 }
 
 static void test_in_addr_ifindex_to_string(void) {
+        log_info("/* %s */", __func__);
+
         test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1");
         test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13");
         test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
@@ -342,6 +419,7 @@ static void test_in_addr_ifindex_from_string_auto(void) {
         int family, ifindex;
         union in_addr_union ua;
 
+        log_info("/* %s */", __func__);
         /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */
 
         assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0);
@@ -385,6 +463,9 @@ static void test_sockaddr_equal(void) {
                 .vm.svm_port = 0,
                 .vm.svm_cid = VMADDR_CID_ANY,
         };
+
+        log_info("/* %s */", __func__);
+
         assert_se(sockaddr_equal(&a, &a));
         assert_se(sockaddr_equal(&a, &b));
         assert_se(sockaddr_equal(&d, &d));
@@ -395,6 +476,8 @@ static void test_sockaddr_equal(void) {
 }
 
 static void test_sockaddr_un_len(void) {
+        log_info("/* %s */", __func__);
+
         static const struct sockaddr_un fs = {
                 .sun_family = AF_UNIX,
                 .sun_path = "/foo/bar/waldo",
@@ -413,6 +496,8 @@ static void test_in_addr_is_multicast(void) {
         union in_addr_union a, b;
         int f;
 
+        log_info("/* %s */", __func__);
+
         assert_se(in_addr_from_string_auto("192.168.3.11", &f, &a) >= 0);
         assert_se(in_addr_is_multicast(f, &a) == 0);
 
@@ -429,6 +514,8 @@ static void test_in_addr_is_multicast(void) {
 static void test_getpeercred_getpeergroups(void) {
         int r;
 
+        log_info("/* %s */", __func__);
+
         r = safe_fork("(getpeercred)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
         assert_se(r >= 0);
 
@@ -497,6 +584,8 @@ static void test_passfd_read(void) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
         int r;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
 
         r = safe_fork("(passfd_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
@@ -544,6 +633,8 @@ static void test_passfd_contents_read(void) {
         static const char wire_contents[] = "test contents on the wire";
         int r;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
 
         r = safe_fork("(passfd_contents_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
@@ -595,6 +686,8 @@ static void test_receive_nopassfd(void) {
         static const char wire_contents[] = "no fd passed here";
         int r;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
 
         r = safe_fork("(receive_nopassfd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
@@ -631,6 +724,8 @@ static void test_send_nodata_nofd(void) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
         int r;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
 
         r = safe_fork("(send_nodata_nofd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
@@ -664,6 +759,8 @@ static void test_send_emptydata(void) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
         int r;
 
+        log_info("/* %s */", __func__);
+
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
 
         r = safe_fork("(send_emptydata)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
@@ -698,12 +795,12 @@ static void test_send_emptydata(void) {
 }
 
 int main(int argc, char *argv[]) {
-
         test_setup_logging(LOG_DEBUG);
 
         test_ifname_valid();
 
         test_socket_address_parse();
+        test_socket_print_unix();
         test_socket_address_parse_netlink();
         test_socket_address_equal();
         test_socket_address_get_path();
index 2b0564d8a05b0d81a7adf4a4c5c898d81fa52b1e..d16fdd90d1bc2898bad5a31198831b3923515769 100644 (file)
@@ -6,11 +6,12 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "macro.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
+#include "path-util.h"
 #include "stat-util.h"
+#include "tmpfile-util.h"
 
 static void test_files_same(void) {
         _cleanup_close_ int fd = -1;
@@ -81,12 +82,87 @@ static void test_fd_is_network_ns(void) {
         assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
 }
 
+static void test_device_major_minor_valid(void) {
+        /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */
+        assert_cc(sizeof(dev_t) == sizeof(uint64_t));
+
+        assert_se(DEVICE_MAJOR_VALID(0U));
+        assert_se(DEVICE_MINOR_VALID(0U));
+
+        assert_se(DEVICE_MAJOR_VALID(1U));
+        assert_se(DEVICE_MINOR_VALID(1U));
+
+        assert_se(!DEVICE_MAJOR_VALID(-1U));
+        assert_se(!DEVICE_MINOR_VALID(-1U));
+
+        assert_se(DEVICE_MAJOR_VALID(1U << 10));
+        assert_se(DEVICE_MINOR_VALID(1U << 10));
+
+        assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1));
+        assert_se(DEVICE_MINOR_VALID((1U << 20) - 1));
+
+        assert_se(!DEVICE_MAJOR_VALID((1U << 12)));
+        assert_se(!DEVICE_MINOR_VALID((1U << 20)));
+
+        assert_se(!DEVICE_MAJOR_VALID(1U << 25));
+        assert_se(!DEVICE_MINOR_VALID(1U << 25));
+
+        assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX));
+        assert_se(!DEVICE_MINOR_VALID(UINT32_MAX));
+
+        assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX));
+        assert_se(!DEVICE_MINOR_VALID(UINT64_MAX));
+
+        assert_se(DEVICE_MAJOR_VALID(major(0)));
+        assert_se(DEVICE_MINOR_VALID(minor(0)));
+}
+
+static void test_device_path_make_canonical_one(const char *path) {
+        _cleanup_free_ char *resolved = NULL, *raw = NULL;
+        struct stat st;
+        dev_t devno;
+        mode_t mode;
+        int r;
+
+        assert_se(stat(path, &st) >= 0);
+        r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved);
+        if (r == -ENOENT) /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we
+                           * run in a container or so? */
+                return;
+
+        assert_se(r >= 0);
+        assert_se(path_equal(path, resolved));
+
+        assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0);
+        assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0);
+
+        assert_se(st.st_rdev == devno);
+        assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT));
+}
+
+static void test_device_path_make_canonical(void) {
+
+        test_device_path_make_canonical_one("/dev/null");
+        test_device_path_make_canonical_one("/dev/zero");
+        test_device_path_make_canonical_one("/dev/full");
+        test_device_path_make_canonical_one("/dev/random");
+        test_device_path_make_canonical_one("/dev/urandom");
+        test_device_path_make_canonical_one("/dev/tty");
+
+        if (is_device_node("/run/systemd/inaccessible/chr") > 0) {
+                test_device_path_make_canonical_one("/run/systemd/inaccessible/chr");
+                test_device_path_make_canonical_one("/run/systemd/inaccessible/blk");
+        }
+}
+
 int main(int argc, char *argv[]) {
         test_files_same();
         test_is_symlink();
         test_path_is_fs_type();
         test_path_is_temporary_fs();
         test_fd_is_network_ns();
+        test_device_major_minor_valid();
+        test_device_path_make_canonical();
 
         return 0;
 }
diff --git a/src/test/test-static-destruct.c b/src/test/test-static-destruct.c
new file mode 100644 (file)
index 0000000..eb0523d
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "static-destruct.h"
+#include "tests.h"
+
+static int foo = 0;
+static int bar = 0;
+static int baz = 0;
+static char* memory = NULL;
+
+static void test_destroy(int *b) {
+        (*b)++;
+}
+
+STATIC_DESTRUCTOR_REGISTER(foo, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(bar, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(bar, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(baz, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(baz, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(baz, test_destroy);
+STATIC_DESTRUCTOR_REGISTER(memory, freep);
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_INFO);
+
+        assert_se(memory = strdup("hallo"));
+
+        assert_se(foo == 0 && bar == 0 && baz == 0);
+        static_destruct();
+        assert_se(foo == 1 && bar == 2 && baz == 3);
+
+        return EXIT_SUCCESS;
+}
index 28dadd0c5b4219651a1d0ad7e8a11ac689f34d74..83a66e8772382cfb05da9e5b4a91e272d5ed392d 100755 (executable)
@@ -1,10 +1,10 @@
 #!/usr/bin/env python3
-#  SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1+
 #
-#  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 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.
 
 import os
 import sys
index 7edf7681c25f7db8b252c687da6ff1c4d33d760c..958d3694303d5480d36a65ae017dfa205d8c29ca 100644 (file)
@@ -5,11 +5,11 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
-#include "tests.h"
 #include "macro.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 static void test_default_term_for_tty(void) {
index 7f288e54ceff72d86e3fa0d6e8e6370d399dd3cc..b5268716554bbc981975a2c7b2ad2d2a6a2f3809 100644 (file)
@@ -14,6 +14,7 @@
 #include "process-util.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 int main(int argc, char** argv) {
index 1b243d03efb3858f728b98da0aeb98081c3df34c..6ab5758edec6cd2110d7a2790a538bd294bce94f 100644 (file)
@@ -16,7 +16,7 @@ static void test_mount_points_list(const char *fname) {
         log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/self/mountinfo");
 
         if (fname)
-                fname = testdata_fname = path_join(NULL, get_testdata_dir(), fname);
+                fname = testdata_fname = path_join(get_testdata_dir(), fname);
 
         LIST_HEAD_INIT(mp_list_head);
         assert_se(mount_points_list_get(fname, &mp_list_head) >= 0);
@@ -38,7 +38,7 @@ static void test_swap_list(const char *fname) {
         log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/swaps");
 
         if (fname)
-                fname = testdata_fname = path_join(NULL, get_testdata_dir(), fname);
+                fname = testdata_fname = path_join(get_testdata_dir(), fname);
 
         LIST_HEAD_INIT(mp_list_head);
         assert_se(swap_list_get(fname, &mp_list_head) >= 0);
index 493ca50220a366d50d3e788551e0888c57ccb1df..13c289270de8c955c1faccdd241bccddf8bcab7f 100644 (file)
@@ -7,12 +7,12 @@
 #include <sys/capability.h>
 #include <unistd.h>
 
-#include "alloc-util.h"
 #include "all-units.h"
+#include "alloc-util.h"
 #include "capability-util.h"
 #include "conf-parser.h"
+#include "env-file.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "hashmap.h"
 #include "hostname-util.h"
@@ -26,6 +26,7 @@
 #include "strv.h"
 #include "test-helper.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 #include "util.h"
 
index b291aa0f0455c85b02a95b9cc3591f01d6782487..801824ad6771ae4c6053220d53ec0f59c574ad74 100644 (file)
@@ -191,7 +191,7 @@ static void test_get_group_creds_one(const char *id, const char *name, gid_t gid
         assert_se(rgid == gid);
 }
 
-int main(int argc, char*argv[]) {
+int main(int argc, char *argv[]) {
         test_uid_to_name_one(0, "root");
         test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME);
         test_uid_to_name_one(0xFFFF, "65535");
index eeee09a7d2b1cb55b523b3c86a41cf306a4b0e9e..3c1b5f9b413d964506ab6600e253e25c5ba40836 100644 (file)
@@ -8,6 +8,7 @@
 #include "def.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "missing_syscall.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
index 2d93e65be21aea37ac69e7e9ca13ae321f8c08b3..3e6df96c5df5f51917b015990be365f04845f658 100644 (file)
@@ -8,11 +8,11 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "xattr-util.h"
 
 static void test_fgetxattrat_fake(void) {
index a79185a59ae2a26133c898bdfc007a0cddc5effa..5a432fea248c0c13496a9eb996ca55428603fe6b 100644 (file)
 #include "clock-util.h"
 #include "def.h"
 #include "fileio-label.h"
+#include "fileio.h"
 #include "fs-util.h"
 #include "hashmap.h"
 #include "list.h"
 #include "main-func.h"
+#include "missing_capability.h"
 #include "path-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
index 405529555564647e5f7173fff07b641b0f63bfc9..70774d757beff0241c9d734b4d59fb835090688c 100644 (file)
@@ -5,8 +5,10 @@
 
 #include "capability-util.h"
 #include "clock-util.h"
+#include "daemon-util.h"
 #include "fd-util.h"
 #include "fs-util.h"
+#include "main-func.h"
 #include "mkdir.h"
 #include "network-util.h"
 #include "process-util.h"
@@ -83,7 +85,8 @@ settime:
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
         const char *user = "systemd-timesync";
         uid_t uid, uid_current;
@@ -95,48 +98,39 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        if (argc != 1) {
-                log_error("This program does not take arguments.");
-                r = -EINVAL;
-                goto finish;
-        }
+        if (argc != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program does not take arguments.");
 
         uid = uid_current = geteuid();
         gid = getegid();
 
         if (uid_current == 0) {
                 r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
-                if (r < 0) {
-                        log_error_errno(r, "Cannot resolve user name %s: %m", user);
-                        goto finish;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Cannot resolve user name %s: %m", user);
         }
 
         r = load_clock_timestamp(uid, gid);
         if (r < 0)
-                goto finish;
+                return r;
 
         /* 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 (uid_current == 0) {
                 r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
                 if (r < 0)
-                        goto finish;
+                        return log_error_errno(r, "Failed to drop privileges: %m");
         }
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
         r = manager_new(&m);
-        if (r < 0) {
-                log_error_errno(r, "Failed to allocate manager: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate manager: %m");
 
         r = manager_connect_bus(m);
-        if (r < 0) {
-                log_error_errno(r, "Could not connect to bus: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not connect to bus: %m");
 
         if (clock_is_localtime(NULL) > 0) {
                 log_info("The system is configured to read the RTC time in the local time zone. "
@@ -149,27 +143,24 @@ int main(int argc, char *argv[]) {
                 log_warning_errno(r, "Failed to parse configuration file: %m");
 
         r = manager_parse_fallback_string(m, NTP_SERVERS);
-        if (r < 0) {
-                log_error_errno(r, "Failed to parse fallback server strings: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse fallback server strings: %m");
 
         log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Daemon is running");
+
+        notify_message = notify_start("READY=1\n"
+                                      "STATUS=Daemon is running",
+                                      NOTIFY_STOPPING);
 
         if (network_is_online()) {
                 r = manager_connect(m);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
         r = sd_event_loop(m->event);
-        if (r < 0) {
-                log_error_errno(r, "Failed to run event loop: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to run event loop: %m");
 
         /* if we got an authoritative time, store it in the file system */
         if (m->sync) {
@@ -178,12 +169,9 @@ int main(int argc, char *argv[]) {
                         log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE);
         }
 
-        sd_event_get_exit_code(m->event, &r);
-
-finish:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
+        (void) sd_event_get_exit_code(m->event, &r);
 
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return r;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index 810b03567e61f78d9000cdbeb21fdb7e384dcd2d..08c57a3fb166f27af2ca57433799589f91e3ad97 100644 (file)
 #include "label.h"
 #include "log.h"
 #include "macro.h"
+#include "main-func.h"
 #include "missing.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-lookup.h"
@@ -172,6 +173,13 @@ static char *arg_replace = NULL;
 static OrderedHashmap *items = NULL, *globs = NULL;
 static Set *unix_sockets = NULL;
 
+STATIC_DESTRUCTOR_REGISTER(items, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(globs, ordered_hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(unix_sockets, set_free_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+
 static int specifier_machine_id_safe(char specifier, void *data, void *userdata, char **ret);
 static int specifier_directory(char specifier, void *data, void *userdata, char **ret);
 
@@ -372,48 +380,39 @@ static struct Item* find_glob(OrderedHashmap *h, const char *match) {
         return NULL;
 }
 
-static void load_unix_sockets(void) {
+static int load_unix_sockets(void) {
+        _cleanup_set_free_free_ Set *sockets = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         if (unix_sockets)
-                return;
+                return 0;
 
         /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
 
-        unix_sockets = set_new(&path_hash_ops);
-        if (!unix_sockets) {
-                log_oom();
-                return;
-        }
+        sockets = set_new(&path_hash_ops);
+        if (!sockets)
+                return log_oom();
 
         f = fopen("/proc/net/unix", "re");
-        if (!f) {
-                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
-                               "Failed to open /proc/net/unix, ignoring: %m");
-                goto fail;
-        }
+        if (!f)
+                return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+                                      "Failed to open /proc/net/unix, ignoring: %m");
 
         /* Skip header */
         r = read_line(f, LONG_LINE_MAX, NULL);
-        if (r < 0) {
-                log_warning_errno(r, "Failed to skip /proc/net/unix header line: %m");
-                goto fail;
-        }
-        if (r == 0) {
-                log_warning("Premature end of file reading /proc/net/unix.");
-                goto fail;
-        }
+        if (r < 0)
+                return log_warning_errno(r, "Failed to skip /proc/net/unix header line: %m");
+        if (r == 0)
+                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Premature end of file reading /proc/net/unix.");
 
         for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *p, *s;
+                _cleanup_free_ char *line = NULL, *s = NULL;
+                char *p;
 
                 r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to read /proc/net/unix line, ignoring: %m");
-                        goto fail;
-                }
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to read /proc/net/unix line, ignoring: %m");
                 if (r == 0) /* EOF */
                         break;
 
@@ -433,36 +432,31 @@ static void load_unix_sockets(void) {
                         continue;
 
                 s = strdup(p);
-                if (!s) {
-                        log_oom();
-                        goto fail;
-                }
+                if (!s)
+                        return log_oom();
 
                 path_simplify(s, false);
 
-                r = set_consume(unix_sockets, s);
-                if (r < 0 && r != -EEXIST) {
-                        log_warning_errno(r, "Failed to add AF_UNIX socket to set, ignoring: %m");
-                        goto fail;
-                }
-        }
+                r = set_consume(sockets, s);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to add AF_UNIX socket to set, ignoring: %m");
 
-        return;
+                TAKE_PTR(s);
+        }
 
-fail:
-        unix_sockets = set_free_free(unix_sockets);
+        unix_sockets = TAKE_PTR(sockets);
+        return 1;
 }
 
 static bool unix_socket_alive(const char *fn) {
         assert(fn);
 
-        load_unix_sockets();
-
-        if (unix_sockets)
-                return !!set_get(unix_sockets, (char*) fn);
+        if (load_unix_sockets() < 0)
+                return true;     /* We don't know, so assume yes */
 
-        /* We don't know, so assume yes */
-        return true;
+        return !!set_get(unix_sockets, (char*) fn);
 }
 
 static int dir_is_mount_point(DIR *d, const char *subdir) {
@@ -1840,7 +1834,7 @@ static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
                         else {
                                 _cleanup_free_ char *de_path = NULL;
 
-                                de_path = path_join(NULL, path, de->d_name);
+                                de_path = path_join(path, de->d_name);
                                 if (!de_path)
                                         q = log_oom();
                                 else
@@ -2329,18 +2323,18 @@ static void item_free_contents(Item *i) {
 #endif
 }
 
-static void item_array_free(ItemArray *a) {
+static ItemArray* item_array_free(ItemArray *a) {
         size_t n;
 
         if (!a)
-                return;
+                return NULL;
 
         for (n = 0; n < a->n_items; n++)
                 item_free_contents(a->items + n);
 
         set_free(a->children);
         free(a->items);
-        free(a);
+        return mfree(a);
 }
 
 static int item_compare(const Item *a, const Item *b) {
@@ -2633,24 +2627,21 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 break;
 
         case CREATE_CHAR_DEVICE:
-        case CREATE_BLOCK_DEVICE: {
-                unsigned major, minor;
-
+        case CREATE_BLOCK_DEVICE:
                 if (!i.argument) {
                         *invalid_config = true;
                         log_error("[%s:%u] Device file requires argument.", fname, line);
                         return -EBADMSG;
                 }
 
-                if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
+                r = parse_dev(i.argument, &i.major_minor);
+                if (r < 0) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
+                        log_error_errno(r, "[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
                         return -EBADMSG;
                 }
 
-                i.major_minor = makedev(major, minor);
                 break;
-        }
 
         case SET_XATTR:
         case RECURSIVE_SET_XATTR:
@@ -3163,9 +3154,11 @@ static int link_parent(ItemArray *a) {
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_hash_func, string_compare_func,
+                                              ItemArray, item_array_free);
+
+static int run(int argc, char *argv[]) {
         _cleanup_strv_free_ char **config_dirs = NULL;
-        int r, k, r_process = 0;
         bool invalid_config = false;
         Iterator iterator;
         ItemArray *a;
@@ -3174,25 +3167,22 @@ int main(int argc, char *argv[]) {
                 PHASE_CREATE,
                 _PHASE_MAX
         } phase;
+        int r, k;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                goto finish;
+                return r;
 
         log_setup_service();
 
         if (arg_user) {
                 r = user_config_paths(&config_dirs);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to initialize configuration directory list: %m");
-                        goto finish;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to initialize configuration directory list: %m");
         } else {
                 config_dirs = strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
-                if (!config_dirs) {
-                        r = log_oom();
-                        goto finish;
-                }
+                if (!config_dirs)
+                        return log_oom();
         }
 
         if (DEBUG_LOGGING) {
@@ -3206,21 +3196,17 @@ int main(int argc, char *argv[]) {
         if (arg_cat_config) {
                 (void) pager_open(arg_pager_flags);
 
-                r = cat_config(config_dirs, argv + optind);
-                goto finish;
+                return cat_config(config_dirs, argv + optind);
         }
 
         umask(0022);
 
         mac_selinux_init();
 
-        items = ordered_hashmap_new(&string_hash_ops);
-        globs = ordered_hashmap_new(&string_hash_ops);
-
-        if (!items || !globs) {
-                r = log_oom();
-                goto finish;
-        }
+        items = ordered_hashmap_new(&item_array_hash_ops);
+        globs = ordered_hashmap_new(&item_array_hash_ops);
+        if (!items || !globs)
+                return log_oom();
 
         /* If command line arguments are specified along with --replace, read all
          * configuration files and insert the positional arguments at the specified
@@ -3233,18 +3219,18 @@ int main(int argc, char *argv[]) {
         else
                 r = parse_arguments(config_dirs, argv + optind, &invalid_config);
         if (r < 0)
-                goto finish;
+                return r;
 
         /* Let's now link up all child/parent relationships */
         ORDERED_HASHMAP_FOREACH(a, items, iterator) {
                 r = link_parent(a);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
         ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
                 r = link_parent(a);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
         /* If multiple operations are requested, let's first run the remove/clean operations, and only then the create
@@ -3265,38 +3251,25 @@ int main(int argc, char *argv[]) {
                 /* The non-globbing ones usually create things, hence we apply them first */
                 ORDERED_HASHMAP_FOREACH(a, items, iterator) {
                         k = process_item_array(a, op);
-                        if (k < 0 && r_process == 0)
-                                r_process = k;
+                        if (k < 0 && r >= 0)
+                                r = k;
                 }
 
                 /* The globbing ones usually alter things, hence we apply them second. */
                 ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
                         k = process_item_array(a, op);
-                        if (k < 0 && r_process == 0)
-                                r_process = k;
+                        if (k < 0 && r >= 0)
+                                r = k;
                 }
         }
 
-finish:
-        pager_close();
-
-        ordered_hashmap_free_with_destructor(items, item_array_free);
-        ordered_hashmap_free_with_destructor(globs, item_array_free);
-
-        free(arg_include_prefixes);
-        free(arg_exclude_prefixes);
-        free(arg_root);
-
-        set_free_free(unix_sockets);
-
-        mac_selinux_finish();
-
-        if (r < 0 || ERRNO_IS_RESOURCE(-r_process))
-                return EXIT_FAILURE;
-        else if (invalid_config)
+        if (ERRNO_IS_RESOURCE(-r))
+                return r;
+        if (invalid_config)
                 return EX_DATAERR;
-        else if (r_process < 0)
+        if (r < 0)
                 return EX_CANTCREAT;
-        else
-                return EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
index 93d4ea4d3f38046a8ad09fc7ec8a252cc4396d97..e4bc5161d5848673870c15b4b94ce6301ff18910 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/ethtool.h>
 
 #include "conf-parser.h"
-#include "missing.h"
+#include "missing_network.h"
 
 struct link_config;
 
index 6703a9d7a3867e40e69fa56f478b17220e492ab0..ac66ffd047464a4bf1da0e8871f9b4e371d9d4ec 100644 (file)
@@ -13,7 +13,7 @@
 #include "fd-util.h"
 #include "link-config.h"
 #include "log.h"
-#include "missing.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "parse-util.h"
index 69bd54244f18923ec793e9dee7e3d89697e89d31..85dba3d099b3fab85590c721a0d32824f5b3acae 100644 (file)
@@ -4,10 +4,6 @@
 #include <stdlib.h>
 #include <sys/ioctl.h>
 
-#if HAVE_LINUX_BTRFS_H
-#include <linux/btrfs.h>
-#endif
-
 #include "device-util.h"
 #include "fd-util.h"
 #include "missing.h"
index f2238ae14edd8e6686dd79ddb423956c58f5f266..d90ebb72599fdfbdf147f02d7c9c9e2d4b5685ea 100644 (file)
@@ -24,6 +24,7 @@
 #include "socket-util.h"
 #include "strxcpyx.h"
 #include "udev-ctrl.h"
+#include "util.h"
 
 /* wire protocol magic must match */
 #define UDEV_CTRL_MAGIC                                0xdead1dea
index c60c02e7fe00a0406f9ef64f53e66efc4ce2391a..bb3e1b9f2381f72d03796eddc8ee740fc606d3c0 100644 (file)
@@ -20,6 +20,7 @@
 #include "netlink-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "signal-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
@@ -64,17 +65,13 @@ struct udev_event *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_net
 }
 
 struct udev_event *udev_event_free(struct udev_event *event) {
-        void *p;
-
         if (!event)
                 return NULL;
 
         sd_device_unref(event->dev);
         sd_device_unref(event->dev_db_clone);
         sd_netlink_unref(event->rtnl);
-        while ((p = hashmap_steal_first_key(event->run_list)))
-                free(p);
-        hashmap_free(event->run_list);
+        hashmap_free_free_key(event->run_list);
         hashmap_free_free_free(event->seclabel_list);
         free(event->program_result);
         free(event->name);
@@ -633,7 +630,7 @@ int udev_event_spawn(struct udev_event *event,
         if (!path_is_absolute(argv[0])) {
                 char *program;
 
-                program = path_join(NULL, UDEVLIBEXECDIR, argv[0]);
+                program = path_join(UDEVLIBEXECDIR, argv[0]);
                 if (!program)
                         return log_oom();
 
@@ -654,6 +651,7 @@ int udev_event_spawn(struct udev_event *event,
                         _exit(EXIT_FAILURE);
 
                 (void) close_all_fds(NULL, 0);
+                (void) rlimit_nofile_safe();
 
                 execve(argv[0], argv, envp);
                 _exit(EXIT_FAILURE);
index 648a102265497b973a4de7aa15638df48e70323a..c11eb8c1acee439498d4d1fbab8b3071bd297870 100644 (file)
@@ -200,10 +200,10 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
                 return log_device_debug_errno(dev, r, "Failed to get id_filename: %m");
 
         util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc));
-        dirname = path_join(NULL, "/run/udev/links/", name_enc);
+        dirname = path_join("/run/udev/links/", name_enc);
         if (!dirname)
                 return log_oom();
-        filename = path_join(NULL, dirname, id_filename);
+        filename = path_join(dirname, id_filename);
         if (!filename)
                 return log_oom();
 
index f6f640a21614384abdb8da095d6f21086aff3562..a9fa04dbf043c2c23f5a29299344035202bb9ee8 100644 (file)
@@ -2407,12 +2407,8 @@ int udev_rules_apply_to_event(
                 case TK_A_RUN_PROGRAM: {
                         _cleanup_free_ char *cmd = NULL;
 
-                        if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL)) {
-                                void *p;
-
-                                while ((p = hashmap_steal_first_key(event->run_list)))
-                                        free(p);
-                        }
+                        if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
+                                hashmap_clear_free_key(event->run_list);
 
                         r = hashmap_ensure_allocated(&event->run_list, NULL);
                         if (r < 0)
index 38035b5c92f20635ebf9d44a6856aac637bc4ba5..f13a08f3f93a347182e171b10932a61bee4f6dee 100644 (file)
@@ -35,7 +35,7 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se
                 if (arg_dry_run)
                         continue;
 
-                filename = path_join(NULL, syspath, "uevent");
+                filename = path_join(syspath, "uevent");
                 if (!filename)
                         return log_oom();
 
index 1dbcf979b171cc6b049b7949b0c6e9a216842b9d..ef0dc564ce6a50509c818ab000e24b7b6a4fe07e 100644 (file)
@@ -14,7 +14,7 @@ int find_device(const char *id, const char *prefix, sd_device **ret) {
         assert(ret);
 
         if (prefix && !path_startswith(id, prefix)) {
-                buf = path_join(NULL, prefix, id);
+                buf = path_join(prefix, id);
                 if (!buf)
                         return -ENOMEM;
                 id = buf;
index c9e3d426b30a17f06de59817b408a8f0ff09c988..fa85f6e2632dc10f74bb15c922d2c3c2901ca4fe 100644 (file)
@@ -534,7 +534,7 @@ static int worker_spawn(Manager *manager, struct event *event) {
         if (r < 0)
                 return log_error_errno(r, "Worker: Failed to enable receiving of device: %m");
 
-        r = safe_fork(NULL, FORK_DEATHSIG, &pid);
+        r = safe_fork("(worker)", FORK_DEATHSIG, &pid);
         if (r < 0) {
                 event->state = EVENT_QUEUED;
                 return log_error_errno(r, "Failed to fork() worker: %m");
@@ -1850,7 +1850,7 @@ static int run(int argc, char *argv[]) {
                         return 0;
 
                 /* child */
-                setsid();
+                (void) setsid();
 
                 r = set_oom_score_adjust(-1000);
                 if (r < 0)
index 5ca8037cb9708afc35945b69165ca8f7262b3b35..490d9f01a9b7fd33383e36547f1989fcbf483dc8 100644 (file)
@@ -12,7 +12,7 @@
 #include "string-util.h"
 #include "util.h"
 
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
         int r, k;
 
         if (argc != 2)
index 7182be4624382bde2e8208e8cef4d2a43aa1e89a..efaa8c28d390e9549e167abc11b204d358fb8a03 100644 (file)
@@ -18,6 +18,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "io-util.h"
@@ -149,7 +150,7 @@ static int keyboard_load_and_wait(const char *vc, const char *map, const char *m
                 log_debug("Executing \"%s\"...", strnull(cmd));
         }
 
-        r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
+        r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -192,7 +193,7 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
                 log_debug("Executing \"%s\"...", strnull(cmd));
         }
 
-        r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
+        r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
index ffe63d5717a4e3a0a7ed9a8769d8bf60d8ee60e8..5da9ce1681de676de9217ee73b0cf23ed806e39c 100644 (file)
@@ -7,6 +7,7 @@
 #include "main-func.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "string-util.h"
diff --git a/test/TEST-25-IMPORT/Makefile b/test/TEST-25-IMPORT/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-25-IMPORT/test.sh b/test/TEST-25-IMPORT/test.sh
new file mode 100755 (executable)
index 0000000..188e723
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="test importd"
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+        dracut_install dd gunzip mv tar diff
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+        cp testsuite.sh $initdir/
+
+        setup_testsuite
+    ) || return 1
+    setup_nspawn_root
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-25-IMPORT/testsuite.sh b/test/TEST-25-IMPORT/testsuite.sh
new file mode 100755 (executable)
index 0000000..2bb96f1
--- /dev/null
@@ -0,0 +1,128 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+export SYSTEMD_PAGER=cat
+
+dd if=/dev/urandom of=/var/tmp/testimage.raw bs=$((1024*1024+7)) count=5
+
+# Test import
+machinectl import-raw /var/tmp/testimage.raw
+machinectl image-status testimage
+test -f /var/lib/machines/testimage.raw
+cmp /var/tmp/testimage.raw /var/lib/machines/testimage.raw
+
+# Test export
+machinectl export-raw testimage /var/tmp/testimage2.raw
+cmp /var/tmp/testimage.raw /var/tmp/testimage2.raw
+rm /var/tmp/testimage2.raw
+
+# Test compressed export (gzip)
+machinectl export-raw testimage /var/tmp/testimage2.raw.gz
+gunzip /var/tmp/testimage2.raw.gz
+cmp /var/tmp/testimage.raw /var/tmp/testimage2.raw
+rm /var/tmp/testimage2.raw
+
+# Test clone
+machinectl clone testimage testimage3
+test -f /var/lib/machines/testimage3.raw
+machinectl image-status testimage3
+test -f /var/lib/machines/testimage.raw
+machinectl image-status testimage
+cmp /var/tmp/testimage.raw /var/lib/machines/testimage.raw
+cmp /var/tmp/testimage.raw /var/lib/machines/testimage3.raw
+
+# Test removal
+machinectl remove testimage
+! test -f /var/lib/machines/testimage.raw
+! machinectl image-status testimage
+
+# Test export of clone
+machinectl export-raw testimage3 /var/tmp/testimage3.raw
+cmp /var/tmp/testimage.raw /var/tmp/testimage3.raw
+rm /var/tmp/testimage3.raw
+
+# Test rename
+machinectl rename testimage3 testimage4
+test -f /var/lib/machines/testimage4.raw
+machinectl image-status testimage4
+! test -f /var/lib/machines/testimage3.raw
+! machinectl image-status testimage3
+cmp /var/tmp/testimage.raw /var/lib/machines/testimage4.raw
+
+# Test export of rename
+machinectl export-raw testimage4 /var/tmp/testimage4.raw
+cmp /var/tmp/testimage.raw /var/tmp/testimage4.raw
+rm /var/tmp/testimage4.raw
+
+# Test removal
+machinectl remove testimage4
+! test -f /var/lib/machines/testimage4.raw
+! machinectl image-status testimage4
+
+# → And now, let's test directory trees ← #
+
+# Set up a directory we can import
+mkdir /var/tmp/scratch
+mv /var/tmp/testimage.raw /var/tmp/scratch/
+touch /var/tmp/scratch/anotherfile
+mkdir /var/tmp/scratch/adirectory
+echo "piep" > /var/tmp/scratch/adirectory/athirdfile
+
+# Test import-fs
+machinectl import-fs /var/tmp/scratch/
+test -d /var/lib/machines/scratch
+machinectl image-status scratch
+
+# Test export-tar
+machinectl export-tar scratch /var/tmp/scratch.tar.gz
+test -f /var/tmp/scratch.tar.gz
+mkdir /var/tmp/extract
+(cd /var/tmp/extract ; tar xzf /var/tmp/scratch.tar.gz)
+diff -r /var/tmp/scratch/ /var/tmp/extract/
+rm -rf /var/tmp/extract
+
+# Test import-tar
+machinectl import-tar /var/tmp/scratch.tar.gz scratch2
+test -d /var/lib/machines/scratch2
+machinectl image-status scratch2
+diff -r /var/tmp/scratch/ /var/lib/machines/scratch2
+
+# Test removal
+machinectl remove scratch
+! test -f /var/lib/machines/scratch
+! machinectl image-status scratch
+
+# Test clone
+machinectl clone scratch2 scratch3
+test -d /var/lib/machines/scratch2
+machinectl image-status scratch2
+test -d /var/lib/machines/scratch3
+machinectl image-status scratch3
+diff -r /var/tmp/scratch/ /var/lib/machines/scratch3
+
+# Test removal
+machinectl remove scratch2
+! test -f /var/lib/machines/scratch2
+! machinectl image-status scratch2
+
+# Test rename
+machinectl rename scratch3 scratch4
+test -d /var/lib/machines/scratch4
+machinectl image-status scratch4
+! test -f /var/lib/machines/scratch3
+! machinectl image-status scratch3
+diff -r /var/tmp/scratch/ /var/lib/machines/scratch4
+
+# Test removal
+machinectl remove scratch4
+! test -f /var/lib/machines/scratch4
+! machinectl image-status scratch4
+
+rm -rf /var/tmp/scratch
+
+echo OK > /testok
+
+exit 0
index 19226df80621846226a4889e684b0b405120981b..5a8d41eb68385e2949940b80752062eb4207e492 100644 (file)
@@ -76,6 +76,7 @@ FOUSourcePort=
 IPv6RapidDeploymentPrefix=
 ERSPANIndex=
 SerializeTunneledPackets=
+ISATAP=
 [VXLAN]
 UDP6ZeroChecksumRx=
 ARPProxy=
index b0502175f38fac68866ea49efe6a349cc5713880..36646ec0ff04686cdf2f9f38186a7e924efa74f1 100644 (file)
@@ -8,4 +8,4 @@ From= 192.168.100.18
 Priority=111
 SourcePort = 1123-1150
 DestinationPort = 3224-3290
-Protocol = tcp
+IPProtocol = tcp
diff --git a/test/fuzz/fuzz-network-parser/25-neighbor-section.network b/test/fuzz/fuzz-network-parser/25-neighbor-section.network
new file mode 100644 (file)
index 0000000..dd750dd
--- /dev/null
@@ -0,0 +1,6 @@
+[Match]
+Name=dummy98
+
+[Neighbor]
+Address=2004:da8:1:0::
+MACAddress=00:00:5e:00:02:00
index 84f221d538549aaaeec91bf1276f66ff57d4d6b2..81b372fb6d091e78dadd8762001f360544f8d51b 100644 (file)
@@ -9,3 +9,4 @@ Cost=400
 HairPin = true
 FastLeave = true
 UnicastFlood = true
+MulticastToUnicast = true
index 7508f693ddbec6cce301010ee7828bd357648ad4..cab87bf98f2e632ab7dcc49cd3d4b746dde35428 100644 (file)
@@ -6,6 +6,7 @@ UnicastFlood=
 FastLeave=
 Priority=
 AllowPortToBeRoot=
+MulticastToUnicast=
 [Match]
 KernelVersion=
 Type=
@@ -152,7 +153,8 @@ Priority=
 FirewallMark=
 SourcePort=
 DestinationPort=
-Protocol=
+IPProtocol=
+InvertRule=
 [IPv6PrefixDelegation]
 RouterPreference=
 DNSLifetimeSec=
@@ -163,6 +165,9 @@ EmitDNS=
 EmitDomains=
 Managed=
 OtherInformation=
+[Neighbor]
+Address=
+MacAddress=
 [IPv6AddressLabel]
 Label=
 Prefix=
index f454fd313ec63044a4ac823bc509f28a43817bc2..4d7526f63619d37f626f9270d654ce5c8e34f385 100644 (file)
@@ -417,6 +417,7 @@ Group=
 GroupForwardMask=
 GroupPolicyExtension=
 HairPin=
+MulticastToUnicast=
 HelloTimeSec=
 HomeAddress=
 Host=
@@ -442,6 +443,7 @@ Independent=
 InitialAdvertisedReceiveWindow=
 InitialCongestionWindow=
 InputKey=
+InvertRule=
 KernelCommandLine=
 KernelVersion=
 Key=
index bf02e39f4320446060410d9cb31dd497f591c69e..d98bfb80d2d973827c9ae76bbbefb2b58978cca3 100644 (file)
@@ -18,6 +18,8 @@ test_data_files = '''
         hwdb/10-bad.hwdb
         journal-data/journal-1.txt
         journal-data/journal-2.txt
+        nomem.slice
+        nomemleaf.service
         parent-deep.slice
         parent.slice
         sched_idle_bad.service
diff --git a/test/nomem.slice b/test/nomem.slice
new file mode 100644 (file)
index 0000000..9c5d208
--- /dev/null
@@ -0,0 +1,5 @@
+[Unit]
+Description=Nomem Parent Slice
+
+[Slice]
+DisableControllers=memory
diff --git a/test/nomemleaf.service b/test/nomemleaf.service
new file mode 100644 (file)
index 0000000..3cbaccb
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=Nomem Leaf Service
+
+[Service]
+Slice=nomem.slice
+Type=oneshot
+ExecStart=/bin/true
+IOWeight=200
+MemoryAccounting=true
diff --git a/test/test-network/conf/25-fibrule-invert.network b/test/test-network/conf/25-fibrule-invert.network
new file mode 100644 (file)
index 0000000..bcca0c2
--- /dev/null
@@ -0,0 +1,10 @@
+[Match]
+Name=test1
+
+[RoutingPolicyRule]
+TypeOfService=0x08
+Table=7
+From= 192.168.100.18
+Priority=111
+IPProtocol = tcp
+InvertRule=true
index b0502175f38fac68866ea49efe6a349cc5713880..36646ec0ff04686cdf2f9f38186a7e924efa74f1 100644 (file)
@@ -8,4 +8,4 @@ From= 192.168.100.18
 Priority=111
 SourcePort = 1123-1150
 DestinationPort = 3224-3290
-Protocol = tcp
+IPProtocol = tcp
diff --git a/test/test-network/conf/25-isatap-tunnel.netdev b/test/test-network/conf/25-isatap-tunnel.netdev
new file mode 100644 (file)
index 0000000..3aa882a
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=isataptun99
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
+ISATAP=true
diff --git a/test/test-network/conf/25-neighbor-section.network b/test/test-network/conf/25-neighbor-section.network
new file mode 100644 (file)
index 0000000..d90802f
--- /dev/null
@@ -0,0 +1,10 @@
+[Match]
+Name=dummy98
+
+[Neighbor]
+Address=192.168.10.1
+MACAddress=00:00:5e:00:02:65
+
+[Neighbor]
+Address=2004:da8:1:0::1
+MACAddress=00:00:5e:00:02:66
index 84f221d538549aaaeec91bf1276f66ff57d4d6b2..81b372fb6d091e78dadd8762001f360544f8d51b 100644 (file)
@@ -9,3 +9,4 @@ Cost=400
 HairPin = true
 FastLeave = true
 UnicastFlood = true
+MulticastToUnicast = true
diff --git a/test/test-network/conf/isatap.network b/test/test-network/conf/isatap.network
new file mode 100644 (file)
index 0000000..e8d03ed
--- /dev/null
@@ -0,0 +1,5 @@
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=isataptun99
index 806f4a496c4930e0499609583afed13d8dc4e9c6..65cc43e8b6b2b3bbed5454b9b878d9090b63da35 100755 (executable)
@@ -3,15 +3,15 @@
 # systemd-networkd tests
 
 import os
-import sys
-import unittest
-import subprocess
-import time
 import re
 import shutil
 import signal
 import socket
+import subprocess
+import sys
 import threading
+import time
+import unittest
 from shutil import copytree
 
 network_unit_file_path='/run/systemd/network'
@@ -61,6 +61,15 @@ class Utilities():
         with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
             return f.readline().strip()
 
+    def read_bridge_port_attr(self, bridge, link, attribute):
+
+        path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
+        path_port = 'lower_' + link + '/brport'
+        path = os.path.join(path_bridge, path_port)
+
+        with open(os.path.join(path, attribute)) as f:
+            return f.readline().strip()
+
     def link_exits(self, link):
         return os.path.exists(os.path.join('/sys/class/net', link))
 
@@ -104,15 +113,16 @@ class Utilities():
 
             os.remove(pid_file)
 
-    def search_words_in_file(self, word):
+    def search_words_in_dnsmasq_log(self, words, show_all=False):
         if os.path.exists(dnsmasq_log_file):
             with open (dnsmasq_log_file) as in_file:
                 contents = in_file.read()
-                print(contents)
-                for part in contents.split():
-                    if word in part:
+                if show_all:
+                    print(contents)
+                for line in contents.split('\n'):
+                    if words in line:
                         in_file.close()
-                        print("%s, %s" % (word, part))
+                        print("%s, %s" % (words, line))
                         return True
         return False
 
@@ -132,6 +142,7 @@ class Utilities():
         else:
             subprocess.check_call('systemctl restart systemd-networkd', shell=True)
         time.sleep(5)
+        print()
 
 global ip
 global port
@@ -162,21 +173,82 @@ class DHCPServer(threading.Thread):
 
 class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
-    links =['bridge99', 'bond99', 'bond99', 'vlan99', 'test1', 'macvtap99',
-            'macvlan99', 'ipvlan99', 'vxlan99', 'veth99', 'vrf99', 'tun99',
-            'tap99', 'vcan99', 'geneve99', 'dummy98', 'ipiptun99', 'sittun99', '6rdtun99',
-            'gretap99', 'vtitun99', 'vti6tun99','ip6tnl99', 'gretun99', 'ip6gretap99',
-            'wg99', 'dropin-test', 'erspan-test']
-
-    units = ['25-bridge.netdev', '25-bond.netdev', '21-vlan.netdev', '11-dummy.netdev', '21-vlan.network',
-             '21-macvtap.netdev', 'macvtap.network', '21-macvlan.netdev', 'macvlan.network', 'vxlan.network',
-             '25-vxlan.netdev', '25-ipvlan.netdev', 'ipvlan.network', '25-veth.netdev', '25-vrf.netdev',
-             '25-tun.netdev', '25-tun.netdev', '25-vcan.netdev', '25-geneve.netdev', '25-ipip-tunnel.netdev',
-             '25-ip6tnl-tunnel.netdev', '25-ip6gre-tunnel.netdev', '25-sit-tunnel.netdev', '25-6rd-tunnel.netdev',
-             '25-erspan-tunnel.netdev', '25-gre-tunnel.netdev', '25-gretap-tunnel.netdev', '25-vti-tunnel.netdev',
-             '25-vti6-tunnel.netdev', '12-dummy.netdev', 'gre.network', 'ipip.network', 'ip6gretap.network',
-             'gretun.network', 'ip6tnl.network', '25-tap.netdev', 'vti6.network', 'vti.network', 'gretap.network',
-             'sit.network', '25-ipip-tunnel-independent.netdev', '25-wireguard.netdev', '6rd.network', '10-dropin-test.netdev']
+    links =[
+        '6rdtun99',
+        'bond99',
+        'bridge99',
+        'dropin-test',
+        'dummy98',
+        'erspan-test',
+        'geneve99',
+        'gretap99',
+        'gretun99',
+        'ip6gretap99',
+        'ip6tnl99',
+        'ipiptun99',
+        'ipvlan99',
+        'isataptun99',
+        'macvlan99',
+        'macvtap99',
+        'sittun99',
+        'tap99',
+        'test1',
+        'tun99',
+        'vcan99',
+        'veth99',
+        'vlan99',
+        'vrf99',
+        'vti6tun99',
+        'vtitun99',
+        'vxlan99',
+        'wg99']
+
+    units = [
+        '10-dropin-test.netdev',
+        '11-dummy.netdev',
+        '12-dummy.netdev',
+        '21-macvlan.netdev',
+        '21-macvtap.netdev',
+        '21-vlan.netdev',
+        '21-vlan.network',
+        '25-6rd-tunnel.netdev',
+        '25-bond.netdev',
+        '25-bridge.netdev',
+        '25-erspan-tunnel.netdev',
+        '25-geneve.netdev',
+        '25-gretap-tunnel.netdev',
+        '25-gre-tunnel.netdev',
+        '25-ip6gre-tunnel.netdev',
+        '25-ip6tnl-tunnel.netdev',
+        '25-ipip-tunnel-independent.netdev',
+        '25-ipip-tunnel.netdev',
+        '25-ipvlan.netdev',
+        '25-isatap-tunnel.netdev',
+        '25-sit-tunnel.netdev',
+        '25-tap.netdev',
+        '25-tun.netdev',
+        '25-vcan.netdev',
+        '25-veth.netdev',
+        '25-vrf.netdev',
+        '25-vti6-tunnel.netdev',
+        '25-vti-tunnel.netdev',
+        '25-vxlan.netdev',
+        '25-wireguard.netdev',
+        '6rd.network',
+        'gre.network',
+        'gretap.network',
+        'gretun.network',
+        'ip6gretap.network',
+        'ip6tnl.network',
+        'ipip.network',
+        'ipvlan.network',
+        'isatap.network',
+        'macvlan.network',
+        'macvtap.network',
+        'sit.network',
+        'vti6.network',
+        'vti.network',
+        'vxlan.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -187,7 +259,6 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     def test_dropin(self):
         self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dropin-test'))
@@ -231,12 +302,12 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     def test_vlan(self):
         self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('vlan99'))
 
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
+        print(output)
         self.assertTrue(output, 'REORDER_HDR')
         self.assertTrue(output, 'LOOSE_BINDING')
         self.assertTrue(output, 'GVRP')
@@ -245,14 +316,12 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     def test_macvtap(self):
         self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('macvtap99'))
 
     def test_macvlan(self):
         self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('macvlan99'))
@@ -260,35 +329,30 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     @expectedFailureIfModuleIsNotAvailable('ipvlan')
     def test_ipvlan(self):
         self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('ipvlan99'))
 
     def test_veth(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('veth99'))
 
     def test_dummy(self):
         self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
 
     def test_tun(self):
         self.copy_unit_to_networkd_unit_path('25-tun.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('tun99'))
 
     def test_tap(self):
         self.copy_unit_to_networkd_unit_path('25-tap.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('tap99'))
@@ -296,7 +360,6 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     @expectedFailureIfModuleIsNotAvailable('vrf')
     def test_vrf(self):
         self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('vrf99'))
@@ -304,7 +367,6 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     @expectedFailureIfModuleIsNotAvailable('vcan')
     def test_vcan(self):
         self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('vcan99'))
@@ -312,7 +374,6 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     @expectedFailureIfModuleIsNotAvailable('wireguard')
     def test_wireguard(self):
         self.copy_unit_to_networkd_unit_path('25-wireguard.netdev')
-
         self.start_networkd()
 
         if shutil.which('wg'):
@@ -322,12 +383,12 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     def test_geneve(self):
         self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('geneve99'))
 
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
+        print(output)
         self.assertTrue(output, '192.168.22.1')
         self.assertTrue(output, '6082')
         self.assertTrue(output, 'udpcsum')
@@ -389,6 +450,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('sittun99'))
 
+    def test_isatap_tunnel(self):
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-isatap-tunnel.netdev', 'isatap.network')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('isataptun99'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "isatap ")
+
     def test_6rd_tunnel(self):
         self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-6rd-tunnel.netdev', '6rd.network')
         self.start_networkd()
@@ -410,18 +482,18 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     def test_tunnel_independent(self):
         self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
-
         self.start_networkd()
+
         self.assertTrue(self.link_exits('ipiptun99'))
 
     def test_vxlan(self):
         self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
-
         self.start_networkd()
 
         self.assertTrue(self.link_exits('vxlan99'))
 
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99']).rstrip().decode('utf-8')
+        print(output)
         self.assertRegex(output, "999")
         self.assertRegex(output, '5555')
         self.assertRegex(output, 'l2miss')
@@ -434,16 +506,37 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'gbp')
 
 class NetworkdNetWorkTests(unittest.TestCase, Utilities):
-    links = ['dummy98', 'test1', 'bond199']
-
-    units = ['12-dummy.netdev', 'test-static.network', 'configure-without-carrier.network', '11-dummy.netdev',
-             '23-primary-slave.network', '23-test1-bond199.network', '11-dummy.netdev', '23-bond199.network',
-             '25-bond-active-backup-slave.netdev', '12-dummy.netdev', '23-active-slave.network',
-             'routing-policy-rule.network', '25-fibrule-port-range.network', '25-address-section.network',
-             '25-address-section-miscellaneous.network', '25-route-section.network', '25-route-type.network',
-             '25-route-tcp-window-settings.network', '25-route-gateway.network', '25-route-gateway-on-link.network',
-             '25-address-link-section.network', '25-ipv6-address-label-section.network', '25-link-section-unmanaged.network',
-             '25-sysctl.network', '25-route-reverse-order.network']
+    links = [
+        'bond199',
+        'dummy98',
+        'test1']
+
+    units = [
+        '11-dummy.netdev',
+        '12-dummy.netdev',
+        '23-active-slave.network',
+        '23-bond199.network',
+        '23-primary-slave.network',
+        '23-test1-bond199.network',
+        '25-address-link-section.network',
+        '25-address-section-miscellaneous.network',
+        '25-address-section.network',
+        '25-bond-active-backup-slave.netdev',
+        '25-fibrule-invert.network',
+        '25-fibrule-port-range.network',
+        '25-ipv6-address-label-section.network',
+        '25-neighbor-section.network',
+        '25-link-section-unmanaged.network',
+        '25-route-gateway.network',
+        '25-route-gateway-on-link.network',
+        '25-route-reverse-order.network',
+        '25-route-section.network',
+        '25-route-tcp-window-settings.network',
+        '25-route-type.network',
+        '25-sysctl.network',
+        'configure-without-carrier.network',
+        'routing-policy-rule.network',
+        'test-static.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -457,6 +550,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
+
         output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '192.168.0.15')
@@ -468,6 +562,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
+
         output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '192.168.0.15')
@@ -480,6 +575,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('bond199'))
+
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, 'active_slave dummy98')
@@ -490,6 +586,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
 
         self.assertTrue(self.link_exits('test1'))
         self.assertTrue(self.link_exits('bond199'))
+
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, 'primary test1')
@@ -499,6 +596,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
+
         output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '111')
@@ -508,11 +606,14 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'oif test1')
         self.assertRegex(output, 'lookup 7')
 
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
     def test_routing_policy_rule_port_range(self):
         self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
+
         output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '111')
@@ -522,6 +623,23 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'tcp')
         self.assertRegex(output, 'lookup 7')
 
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
+    def test_routing_policy_rule_invert(self):
+        self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+
+        output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, '111')
+        self.assertRegex(output, 'not.*?from.*?192.168.100.18')
+        self.assertRegex(output, 'tcp')
+        self.assertRegex(output, 'lookup 7')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
     def test_address_preferred_lifetime_zero_ipv6(self):
         self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
         self.start_networkd()
@@ -658,6 +776,17 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         print(output)
         self.assertRegex(output, '2004:da8:1::/64')
 
+    def test_ipv6_neighbor(self):
+        self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+
+        output = subprocess.check_output(['ip', 'neigh', 'list']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
+        self.assertRegex(output, '2004:da8:1:0::1.*00:00:5e:00:02:66.*PERMANENT')
+
     def test_sysctl(self):
         self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
         self.start_networkd()
@@ -672,11 +801,19 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
 
-class NetworkdNetWorkBrideTests(unittest.TestCase, Utilities):
-    links = ['dummy98', 'test1', 'bridge99']
+class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
+    links = [
+        'bridge99',
+        'dummy98',
+        'test1']
 
-    units = ['11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev', '26-bridge-slave-interface-1.network',
-             '26-bridge-slave-interface-2.network', 'bridge99.network']
+    units = [
+        '11-dummy.netdev',
+        '12-dummy.netdev',
+        '26-bridge.netdev',
+        '26-bridge-slave-interface-1.network',
+        '26-bridge-slave-interface-2.network',
+        'bridge99.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -712,15 +849,22 @@ class NetworkdNetWorkBrideTests(unittest.TestCase, Utilities):
 
         output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'cost 400')
-        self.assertRegex(output, 'hairpin on')
-        self.assertRegex(output, 'flood on')
-        self.assertRegex(output, 'fastleave on')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
+
+        # CONFIG_BRIDGE_IGMP_SNOOPING=y
+        if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
+            self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
 
 class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
     links = ['veth99']
 
-    units = ['23-emit-lldp.network', '24-lldp.network', '25-veth.netdev']
+    units = [
+        '23-emit-lldp.network',
+        '24-lldp.network',
+        '25-veth.netdev']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -743,7 +887,10 @@ class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
 class NetworkdNetworkRATests(unittest.TestCase, Utilities):
     links = ['veth99']
 
-    units = ['25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network']
+    units = [
+        '25-veth.netdev',
+        'ipv6-prefix.network',
+        'ipv6-prefix-veth.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -763,10 +910,18 @@ class NetworkdNetworkRATests(unittest.TestCase, Utilities):
         self.assertRegex(output, '2002:da8:1:0')
 
 class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
-    links = ['veth99', 'dummy98']
-
-    units = ['25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network', '12-dummy.netdev', '24-search-domain.network',
-             'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network']
+    links = [
+        'dummy98',
+        'veth99']
+
+    units = [
+        '12-dummy.netdev',
+        '24-search-domain.network',
+        '25-veth.netdev',
+        'dhcp-client.network',
+        'dhcp-client-timezone-router.network',
+        'dhcp-server.network',
+        'dhcp-server-timezone-router.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -781,8 +936,6 @@ class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
 
         self.assertTrue(self.link_exits('veth99'))
 
-        time.sleep(5)
-
         output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '192.168.5.*')
@@ -815,14 +968,24 @@ class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'Europe/Berlin')
 
 class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
-    links = ['veth99', 'dummy98']
-
-    units = ['25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv6-only.network',
-             'dhcp-client-ipv4-only-ipv6-disabled.network', 'dhcp-client-ipv4-only.network',
-             'dhcp-client-ipv4-dhcp-settings.network', 'dhcp-client-anonymize.network',
-             'dhcp-client-ipv6-rapid-commit.network', 'dhcp-client-route-table.network',
-             'dhcp-v4-server-veth-peer.network', 'dhcp-client-listen-port.network',
-             'dhcp-client-route-metric.network', 'dhcp-client-critical-connection.network']
+    links = [
+        'dummy98',
+        'veth99']
+
+    units = [
+        '25-veth.netdev',
+        'dhcp-client-anonymize.network',
+        'dhcp-client-critical-connection.network',
+        'dhcp-client-ipv4-dhcp-settings.network',
+        'dhcp-client-ipv4-only-ipv6-disabled.network',
+        'dhcp-client-ipv4-only.network',
+        'dhcp-client-ipv6-only.network',
+        'dhcp-client-ipv6-rapid-commit.network',
+        'dhcp-client-listen-port.network',
+        'dhcp-client-route-metric.network',
+        'dhcp-client-route-table.network',
+        'dhcp-server-veth-peer.network',
+        'dhcp-v4-server-veth-peer.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -893,10 +1056,10 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         print(output)
         self.assertRegex(output, 'default.*dev veth99 proto dhcp')
 
-        self.search_words_in_file('vendor class: SusantVendorTest')
-        self.search_words_in_file('client MAC address: 12:34:56:78:9a:bc')
-        self.search_words_in_file('client provides name: test-hostname')
-        self.search_words_in_file('26:mtu')
+        self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
+        self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
+        self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
+        self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
 
     def test_dhcp6_client_settings_rapidcommit_true(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
@@ -909,8 +1072,7 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '12:34:56:78:9a:bc')
-
-        self.assertTrue(self.search_words_in_file('14:rapid-commit'))
+        self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
 
     def test_dhcp6_client_settings_rapidcommit_false(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
@@ -923,8 +1085,7 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '12:34:56:78:9a:bc')
-
-        self.assertFalse(self.search_words_in_file('14:rapid-commit'))
+        self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
 
     def test_dhcp_client_settings_anonymize(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
@@ -933,12 +1094,14 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         self.assertTrue(self.link_exits('veth99'))
 
         self.start_dnsmasq()
-        self.assertFalse(self.search_words_in_file('VendorClassIdentifier=SusantVendorTest'))
-        self.assertFalse(self.search_words_in_file('test-hostname'))
-        self.assertFalse(self.search_words_in_file('26:mtu'))
+
+        self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
+        self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
+        self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
 
     def test_dhcp_client_listen_port(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
+
         dh_server = DHCPServer("dhcp_server")
         dh_server.start()
 
@@ -957,39 +1120,40 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
     def test_dhcp_route_table_id(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
         self.start_networkd()
-        self.start_dnsmasq()
 
         self.assertTrue(self.link_exits('veth99'))
 
+        self.start_dnsmasq()
+
         output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
         print(output)
-
         self.assertRegex(output, 'veth99 proto dhcp')
         self.assertRegex(output, '192.168.5.1')
 
     def test_dhcp_route_metric(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
         self.start_networkd()
-        self.start_dnsmasq()
 
         self.assertTrue(self.link_exits('veth99'))
 
+        self.start_dnsmasq()
+
         output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
         print(output)
-
         self.assertRegex(output, 'metric 24')
 
     def test_dhcp_route_criticalconnection_true(self):
         self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
         self.start_networkd()
-        self.start_dnsmasq()
 
         self.assertTrue(self.link_exits('veth99'))
 
+        self.start_dnsmasq()
+
         output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
         print(output)
-
         self.assertRegex(output, '192.168.5.*')
+
         # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
         self.stop_dnsmasq(dnsmasq_pid_file)
 
index b65869d02b6cd1d0b14dffe70828e270b9047aee..ca1e13df9a9894540a08e0f1e27ac7e74d09eeaa 100755 (executable)
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
 # SPDX-License-Identifier: MIT
 #
 # This file is distributed under the MIT license, see below.
index ea151601075adc234f89fb199fe7f3e89234de1b..4e8593f320099b96c568baee3eff57ad762f0e77 100644 (file)
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-#  -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
 # SPDX-License-Identifier: LGPL-2.1+
 
 from __future__ import print_function
@@ -16,7 +15,6 @@ class sd_dump_hashmaps(gdb.Command):
                 d = gdb.parse_and_eval("hashmap_debug_list")
                 all_entry_sizes = gdb.parse_and_eval("all_entry_sizes")
                 all_direct_buckets = gdb.parse_and_eval("all_direct_buckets")
-                hashmap_base_t = gdb.lookup_type("HashmapBase")
                 uchar_t = gdb.lookup_type("unsigned char")
                 ulong_t = gdb.lookup_type("unsigned long")
                 debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
index aca9ab1fe91e3123ac3a99355efb699d715283de..5392df0ebbbb2105f3cac4f9fc183949e0b24c07 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1+
 
-"""Generate %-from-name.gperf from %-list.txt
+"""
+Generate %-from-name.gperf from %-list.txt
 """
 
 import sys
index 8b85ef40f3ec2987e7ec99257a0e8ce8d038560a..8703c8a37bd073f6938f706bb36f8f12b4261749 100755 (executable)
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-#  -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
 # SPDX-License-Identifier: LGPL-2.1+
 
 import sys
index ab52bb2c55d42282c506ea213957154d251c84a2..78506cbf396040c7b5a5a8e44ee66e8404bb9392 100755 (executable)
@@ -9,7 +9,23 @@ cd "$@"/docs/
         for f in *.md ; do
                 if [ "x$f" != "xindex.md" ] ; then
                         t=`grep "^# " "$f" | head -n 1 | sed -e 's/^#\s*//'`
-                        u="https://systemd.io/"`echo "$f" | sed -e 's/.md$//'`
+
+                        if [ "x$f" = "xCODE_OF_CONDUCT.md" -o "x$f" = "xCONTRIBUTING.md" ] ; then
+                                # For some reason GitHub refuses to generate
+                                # HTML versions of these two documents,
+                                # probably because they are in some way special
+                                # in GitHub behaviour (as they are shown as
+                                # links in the issue submission form). Let's
+                                # work around this limitation by linking to
+                                # their repository browser version
+                                # instead. This might not even be such a bad
+                                # thing, given that the issue submission form
+                                # and our index file thus link to the same
+                                # version.
+                                u="https://github.com/systemd/systemd/blob/master/docs/$f"
+                        else
+                                u="https://systemd.io/"`echo "$f" | sed -e 's/.md$//'`
+                        fi
                         echo "* [$t]($u)"
                 fi
         done
index 7ed98cb4e006bf84caa0ad424bbba50b16853b2f..66027af02e526ad4e1a45fd4097fbbb8a7c7867d 100755 (executable)
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-#  -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
 # SPDX-License-Identifier: LGPL-2.1+
 
 import collections
index 42a48bc98ccaeab367d377dd1f83e11a1fd9801b..c4551c6f61d000fff9dce3c7be0fa162c57fee97 100755 (executable)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
-#  -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
-#  SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1+
 
 from __future__ import print_function
 import collections
index 19e343b4e3a36b20e5f27f41155c332a34817eae..f399e7493ca2461647a3ccf2f76002376dd5d8ab 100755 (executable)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
-#  -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
-#  SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1+
 
 from lxml import etree as tree
 
diff --git a/travis-ci/managers/debian.sh b/travis-ci/managers/debian.sh
new file mode 100755 (executable)
index 0000000..af2f0da
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+# Run this script from the root of the systemd's git repository
+# or set REPO_ROOT to a correct path.
+#
+# Example execution on Fedora:
+# dnf install docker
+# systemctl start docker
+# export CONT_NAME="my-fancy-container"
+# travis-ci/managers/debian.sh SETUP RUN CLEANUP
+
+PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
+DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
+CONT_NAME="${CONT_NAME:-debian-$DEBIAN_RELEASE-$RANDOM}"
+DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
+DOCKER_RUN="${DOCKER_RUN:-docker run}"
+REPO_ROOT="${REPO_ROOT:-$PWD}"
+ADDITIONAL_DEPS=(python3-libevdev python3-pyparsing clang)
+
+function info() {
+    echo -e "\033[33;1m$1\033[0m"
+}
+
+set -e
+
+source "$(dirname $0)/travis_wait.bash"
+
+for phase in "${PHASES[@]}"; do
+    case $phase in
+        SETUP)
+            info "Setup phase"
+            info "Using Debian $DEBIAN_RELEASE"
+            printf "FROM debian:$DEBIAN_RELEASE\nRUN bash -c 'apt-get -y update && apt-get install -y systemd'\n" | docker build -t debian-with-systemd/latest -
+            info "Starting container $CONT_NAME"
+            $DOCKER_RUN -v $REPO_ROOT:/build:rw \
+                        -w /build --privileged=true --name $CONT_NAME \
+                        -dit --net=host debian-with-systemd/latest /usr/bin/systemd
+            $DOCKER_EXEC bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
+            $DOCKER_EXEC apt-get -y update
+            $DOCKER_EXEC apt-get -y build-dep systemd
+            $DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}"
+            # overlayfs on TravisCI is having trouble delivering inotify events to test-path and test-event.
+            # Let's use tmpfs instead for now.
+            $DOCKER_EXEC mount -t tmpfs tmpfs /tmp
+            ;;
+        RUN)
+            info "Run phase"
+            $DOCKER_EXEC meson --werror -Dtests=unsafe -Dslow-tests=true -Dsplit-usr=true build
+            $DOCKER_EXEC ninja -v -C build
+            $DOCKER_EXEC ninja -C build test
+            $DOCKER_EXEC tools/check-directives.sh
+            ;;
+        RUN_CLANG)
+            docker exec -e CC=clang -e CXX=clang++ -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true -Dsplit-usr=true build
+            $DOCKER_EXEC ninja -v -C build
+            $DOCKER_EXEC ninja -C build test
+            ;;
+        RUN_ASAN|RUN_CLANG_ASAN)
+            if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+                ENV_VARS="-e CC=clang -e CXX=clang++"
+                MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
+            fi
+            docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Db_sanitize=address,undefined -Dsplit-usr=true $MESON_ARGS build
+            $DOCKER_EXEC ninja -v -C build
+
+            # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb.
+            travis_wait docker exec --interactive=false \
+                -e UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 \
+                -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \
+                -e "TRAVIS=$TRAVIS" \
+                -t $CONT_NAME \
+                meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
+            ;;
+        CLEANUP)
+            info "Cleanup phase"
+            docker stop $CONT_NAME
+            docker rm -f $CONT_NAME
+            ;;
+        *)
+            echo >&2 "Unknown phase '$phase'"
+            exit 1
+    esac
+done
index b3ee0281a6bae75d5a5a0d5f84dee53d32ac780b..760ed5b1ea5d0431588f25cfe35c436a8ebe7e35 100755 (executable)
@@ -15,7 +15,7 @@ CONT_NAME="${CONT_NAME:-fedora-$FEDORA_RELEASE-$RANDOM}"
 DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
 DOCKER_RUN="${DOCKER_RUN:-docker run}"
 REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(dnf-plugins-core python2 iputils hostname libasan python3-pyparsing python3-evdev libubsan)
+ADDITIONAL_DEPS=(dnf-plugins-core python2 iputils hostname libasan python3-pyparsing python3-evdev libubsan clang llvm)
 
 function info() {
     echo -e "\033[33;1m$1\033[0m"
@@ -52,9 +52,17 @@ for phase in "${PHASES[@]}"; do
             $DOCKER_EXEC ninja -C build test
             $DOCKER_EXEC tools/check-directives.sh
             ;;
-        RUN_ASAN)
-            $DOCKER_EXEC git clean -dxff
-            $DOCKER_EXEC meson --werror -Dtests=unsafe -Db_sanitize=address,undefined build
+        RUN_CLANG)
+            docker exec -e CC=clang -e CXX=clang++ -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true build
+            $DOCKER_EXEC ninja -v -C build
+            $DOCKER_EXEC ninja -C build test
+            ;;
+        RUN_ASAN|RUN_CLANG_ASAN)
+            if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+                ENV_VARS="-e CC=clang -e CXX=clang++"
+                MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
+            fi
+            docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS build
             $DOCKER_EXEC ninja -v -C build
 
             # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb.
index 5da0c6fa3230dcb888fa6a931795d7d94f9bc59d..3658199cc7e2813ead2252e99df193f8b356c5de 100644 (file)
@@ -7,8 +7,13 @@
 #  the Free Software Foundation; either version 2.1 of the License, or
 #  (at your option) any later version.
 
+# This unit is required for pre-240 versions of systemd that automatically set
+# up /var/lib/machines.raw as loopback-mounted btrfs file system. Later
+# versions don't do that anymore, but let's keep minimal compatibility by
+# mounting the image still, if it exists.
+
 [Unit]
-Description=Virtual Machine and Container Storage
+Description=Virtual Machine and Container Storage (Compatibility)
 ConditionPathExists=/var/lib/machines.raw
 
 [Mount]