]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #17185 from yuwata/ethtool-update
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 23 Oct 2020 06:22:09 +0000 (08:22 +0200)
committerGitHub <noreply@github.com>
Fri, 23 Oct 2020 06:22:09 +0000 (08:22 +0200)
ethtool: add several link modes

714 files changed:
.github/ISSUE_TEMPLATE/Bug_report.md
.github/workflows/build_test.yml
.github/workflows/ubuntu-build-check.sh
NEWS
README.md
TODO
catalog/systemd.be.catalog.in
catalog/systemd.be@latin.catalog.in
catalog/systemd.bg.catalog.in
catalog/systemd.catalog.in
catalog/systemd.da.catalog.in
catalog/systemd.fr.catalog.in
catalog/systemd.hr.catalog.in
catalog/systemd.hu.catalog.in
catalog/systemd.it.catalog.in
catalog/systemd.ko.catalog.in
catalog/systemd.pl.catalog.in
catalog/systemd.pt_BR.catalog.in
catalog/systemd.ru.catalog.in
catalog/systemd.sr.catalog.in
catalog/systemd.zh_CN.catalog.in
catalog/systemd.zh_TW.catalog.in
coccinelle/empty-to-root.cocci
coccinelle/equals-null.cocci
coccinelle/errno-check.cocci [new file with mode: 0644]
coccinelle/flags-set.cocci
coccinelle/in_set.cocci
coccinelle/macros.h [new file with mode: 0644]
coccinelle/not_in_set.cocci
coccinelle/run-coccinelle.sh
coccinelle/strjoin.cocci
coccinelle/systemd-definitions.iso [deleted file]
coccinelle/xsprintf.cocci
coccinelle/zz-drop-braces.cocci [new file with mode: 0644]
docs/BLOCK_DEVICE_LOCKING.md
docs/BOOT_LOADER_SPECIFICATION.md
docs/CODING_STYLE.md
docs/PORTABILITY_AND_STABILITY.md
docs/ROOT_STORAGE_DAEMONS.md
docs/TEMPORARY_DIRECTORIES.md
docs/TRANSIENT-SETTINGS.md
docs/UIDS-GIDS.md
hwdb.d/20-OUI.hwdb
hwdb.d/20-acpi-vendor.hwdb
hwdb.d/20-acpi-vendor.hwdb.patch
hwdb.d/20-pci-classes.hwdb
hwdb.d/20-pci-vendor-model.hwdb
hwdb.d/20-usb-vendor-model.hwdb
hwdb.d/60-autosuspend.hwdb
hwdb.d/60-evdev.hwdb
hwdb.d/60-input-id.hwdb
hwdb.d/60-keyboard.hwdb
hwdb.d/60-sensor.hwdb
hwdb.d/70-joystick.hwdb
hwdb.d/70-mouse.hwdb
hwdb.d/70-pointingstick.hwdb
hwdb.d/70-touchpad.hwdb
hwdb.d/acpi_id_registry.html
hwdb.d/ma-large.txt
hwdb.d/ma-medium.txt
hwdb.d/ma-small.txt
hwdb.d/parse_hwdb.py
hwdb.d/pci.ids
hwdb.d/pnp_id_registry.html
hwdb.d/usb.ids
man/bootctl.xml
man/bootup.xml
man/busctl.xml
man/crypttab.xml
man/dnssec-trust-anchors.d.xml
man/environment.d.xml
man/file-hierarchy.xml
man/homectl.xml
man/html.in
man/hwdb.xml
man/journald.conf.xml
man/kernel-command-line.xml
man/less-variables.xml
man/loginctl.xml
man/logind.conf.xml
man/machine-id.xml
man/machinectl.xml
man/meson.build
man/nss-myhostname.xml
man/oomctl.xml [new file with mode: 0644]
man/oomd.conf.xml [new file with mode: 0644]
man/org.freedesktop.home1.xml
man/org.freedesktop.import1.xml
man/org.freedesktop.login1.xml
man/org.freedesktop.oom1.xml [new file with mode: 0644]
man/org.freedesktop.resolve1.xml
man/org.freedesktop.systemd1.xml
man/os-release.xml
man/portablectl.xml
man/rules/meson.build
man/sd-login.xml
man/sd_bus_creds_new_from_pid.xml
man/sd_bus_default.xml
man/sd_bus_message_read_array.xml
man/sd_bus_send.xml
man/sd_event_add_child.xml
man/sd_event_add_defer.xml
man/sd_event_add_inotify.xml
man/sd_event_add_io.xml
man/sd_event_add_signal.xml
man/sd_event_add_time.xml
man/sd_event_exit.xml
man/sd_event_source_set_exit_on_failure.xml [new file with mode: 0644]
man/sd_is_fifo.xml
man/sd_notify.xml
man/sd_pid_get_owner_uid.xml
man/standard-specifiers.xml
man/sysctl.d.xml
man/systemctl.xml
man/systemd-ask-password-console.service.xml
man/systemd-ask-password.xml
man/systemd-cgls.xml
man/systemd-cgtop.xml
man/systemd-cryptsetup-generator.xml
man/systemd-cryptsetup@.service.xml
man/systemd-delta.xml
man/systemd-detect-virt.xml
man/systemd-dissect.xml
man/systemd-firstboot.xml
man/systemd-fstab-generator.xml
man/systemd-hibernate-resume-generator.xml
man/systemd-homed.service.xml
man/systemd-journald.service.xml
man/systemd-machine-id-commit.service.xml
man/systemd-machine-id-setup.xml
man/systemd-machined.service.xml
man/systemd-modules-load.service.xml
man/systemd-mount.xml
man/systemd-notify.xml
man/systemd-nspawn.xml
man/systemd-oomd.service.xml [new file with mode: 0644]
man/systemd-remount-fs.service.xml
man/systemd-resolved.service.xml
man/systemd-sysctl.service.xml
man/systemd-tmpfiles.xml
man/systemd-tty-ask-password-agent.xml
man/systemd-update-done.service.xml
man/systemd-volatile-root.service.xml
man/systemd.device.xml
man/systemd.dnssd.xml
man/systemd.environment-generator.xml
man/systemd.exec.xml
man/systemd.generator.xml
man/systemd.journal-fields.xml
man/systemd.link.xml
man/systemd.mount.xml
man/systemd.net-naming-scheme.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.offline-updates.xml
man/systemd.resource-control.xml
man/systemd.service.xml
man/systemd.socket.xml
man/systemd.special.xml
man/systemd.unit.xml
man/systemd.xml
man/sysusers.d.xml
man/tmpfiles.d.xml
man/udev.conf.xml
man/udev.xml
man/udev_device_new_from_syspath.xml
man/udevadm.xml
meson.build
meson_options.txt
po/be.po
po/da.po
po/de.po
po/it.po
po/pl.po
presets/90-systemd.preset
rules.d/80-net-setup-link.rules
rules.d/99-systemd.rules.in
semaphoreci/semaphore-runner.sh
shell-completion/bash/meson.build
shell-completion/zsh/_loginctl
src/analyze/analyze-security.c
src/analyze/analyze.c
src/basic/alloc-util.h
src/basic/btrfs-util.c
src/basic/build.h
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/copy.h
src/basic/def.h
src/basic/env-util.c
src/basic/fd-util.c
src/basic/fileio.c
src/basic/fileio.h
src/basic/format-util.h
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/hash-funcs.c
src/basic/hash-funcs.h
src/basic/hashmap.c
src/basic/hashmap.h
src/basic/khash.c
src/basic/linux/ipv6_route.h [new file with mode: 0644]
src/basic/linux/loadavg.h [new file with mode: 0644]
src/basic/log.c
src/basic/log.h
src/basic/macro.h
src/basic/meson.build
src/basic/missing_capability.h
src/basic/missing_syscall.h
src/basic/parse-util.c
src/basic/parse-util.h
src/basic/path-lookup.c
src/basic/path-util.c
src/basic/path-util.h
src/basic/ratelimit.c
src/basic/ratelimit.h
src/basic/rm-rf.c
src/basic/selinux-util.c
src/basic/selinux-util.h
src/basic/set.h
src/basic/socket-label.c
src/basic/string-util.h
src/basic/strv.c
src/basic/strv.h
src/basic/terminal-util.c
src/basic/time-util.h
src/basic/user-util.h
src/basic/virt.c
src/basic/virt.h
src/boot/bootctl.c
src/boot/efi/measure.c
src/busctl/busctl.c
src/cgtop/cgtop.c
src/core/automount.c
src/core/cgroup.c
src/core/cgroup.h
src/core/core-varlink.c
src/core/core-varlink.h
src/core/dbus-cgroup.c
src/core/dbus-execute.c
src/core/dbus-util.c
src/core/dbus-util.h
src/core/device.c
src/core/dynamic-user.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/machine-id-setup.c
src/core/machine-id-setup.h
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/mount-setup.c
src/core/namespace.c
src/core/scope.c
src/core/selinux-setup.c
src/core/service.c
src/core/slice.c
src/core/socket.c
src/core/systemd.pc.in
src/core/unit.c
src/core/unit.h
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup.c
src/fsck/fsck.c
src/home/homectl-fido2.c
src/home/homectl-pkcs11.c
src/home/homectl.c
src/home/homed-home.c
src/home/homed-manager-bus.c
src/home/homed-operation.h
src/home/homework.c
src/home/pam_systemd_home.c
src/hostname/hostnamectl.c
src/import/import-fs.c
src/import/import.c
src/import/pull-common.c
src/import/pull.c
src/journal/compress.c
src/journal/journal-send.c
src/journal/journalctl.c
src/journal/journald-server.c
src/journal/test-journal-stream.c
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-ipv4acd.c
src/libsystemd-network/sd-ipv4ll.c
src/libsystemd-network/sd-lldp.c
src/libsystemd-network/sd-ndisc.c
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd-network/test-dhcp-server.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-bus/bus-container.c
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-cleanup.c
src/libsystemd/sd-bus/test-bus-track.c
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-event/event-source.h
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-hwdb/hwdb-util.c
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-id128/id128-util.c
src/libsystemd/sd-id128/id128-util.h
src/libsystemd/sd-login/test-login.c
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/test-netlink.c
src/libsystemd/sd-resolve/test-resolve.c
src/login/inhibit.c
src/login/loginctl.c
src/login/logind-action.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-session.c
src/login/logind.c
src/machine-id-setup/machine-id-setup-main.c
src/machine/machinectl.c
src/mount/mount-tool.c
src/network/meson.build
src/network/netdev/macsec.c
src/network/netdev/macsec.h
src/network/networkctl.c
src/network/networkd-address-label.c
src/network/networkd-address-label.h
src/network/networkd-address-pool.c
src/network/networkd-address-pool.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-brvlan.c
src/network/networkd-brvlan.h
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp-common.h
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp4.c
src/network/networkd-dhcp4.h
src/network/networkd-dhcp6.c
src/network/networkd-dhcp6.h
src/network/networkd-fdb.c
src/network/networkd-fdb.h
src/network/networkd-ipv4ll.c
src/network/networkd-ipv4ll.h
src/network/networkd-ipv6-proxy-ndp.c
src/network/networkd-ipv6-proxy-ndp.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-lldp-rx.c
src/network/networkd-lldp-rx.h
src/network/networkd-lldp-tx.c
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-mdb.c
src/network/networkd-mdb.h
src/network/networkd-ndisc.c
src/network/networkd-ndisc.h
src/network/networkd-neighbor.c
src/network/networkd-neighbor.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-nexthop.c
src/network/networkd-nexthop.h
src/network/networkd-radv.c
src/network/networkd-radv.h
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-sriov.c
src/network/networkd-sriov.h
src/network/networkd-sysctl.c [new file with mode: 0644]
src/network/networkd-sysctl.h [new file with mode: 0644]
src/network/networkd-util.c
src/network/networkd-util.h
src/network/networkd-wifi.c
src/network/networkd.c
src/network/tc/gred.c
src/network/tc/tc.c
src/network/tc/tc.h
src/network/tc/teql.c
src/network/test-network.c
src/network/test-networkd-conf.c
src/network/test-routing-policy-rule.c
src/nspawn/nspawn-oci.c
src/nspawn/nspawn-setuid.c
src/nspawn/nspawn-setuid.h
src/nspawn/nspawn.c
src/nss-systemd/nss-systemd.c
src/oom/meson.build [new file with mode: 0644]
src/oom/oomctl.c [new file with mode: 0644]
src/oom/oomd-manager-bus.c [new file with mode: 0644]
src/oom/oomd-manager-bus.h [new file with mode: 0644]
src/oom/oomd-manager.c [new file with mode: 0644]
src/oom/oomd-manager.h [new file with mode: 0644]
src/oom/oomd-util.c [new file with mode: 0644]
src/oom/oomd-util.h [new file with mode: 0644]
src/oom/oomd.c [new file with mode: 0644]
src/oom/oomd.conf [new file with mode: 0644]
src/oom/org.freedesktop.oom1.conf [new file with mode: 0644]
src/oom/org.freedesktop.oom1.service [new file with mode: 0644]
src/oom/test-oomd-util.c [new file with mode: 0644]
src/partition/repart.c
src/partition/test-repart.sh
src/portable/portable.c
src/portable/portablectl.c
src/resolve/meson.build
src/resolve/resolv.conf
src/resolve/resolvectl.c
src/resolve/resolved-bus.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-packet.h
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-stub.c
src/resolve/resolved-dnssd.c
src/resolve/resolved-manager.c
src/resolve/resolved-resolv-conf.c
src/resolve/resolved-resolv-conf.h
src/resolve/resolved-varlink.c
src/resolve/resolved.conf.in
src/run/run.c
src/shared/bootspec.c
src/shared/bus-get-properties.c
src/shared/bus-get-properties.h
src/shared/bus-map-properties.c
src/shared/bus-map-properties.h
src/shared/bus-unit-util.c
src/shared/bus-unit-util.h
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/calendarspec.c
src/shared/chown-recursive.c
src/shared/clean-ipc.c
src/shared/clock-util.c
src/shared/condition.c
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/daemon-util.h
src/shared/dissect-image.c
src/shared/dns-domain.c
src/shared/dns-domain.h
src/shared/ethtool-util.c
src/shared/ethtool-util.h
src/shared/format-table.c
src/shared/format-table.h
src/shared/fstab-util.c
src/shared/generator.c
src/shared/idn-util.c [new file with mode: 0644]
src/shared/idn-util.h [new file with mode: 0644]
src/shared/json.c
src/shared/local-addresses.c
src/shared/logs-show.c
src/shared/meson.build
src/shared/netif-naming-scheme.c
src/shared/netif-naming-scheme.h
src/shared/pager.c
src/shared/pkcs11-util.c
src/shared/pretty-print.c
src/shared/psi-util.c [new file with mode: 0644]
src/shared/psi-util.h [new file with mode: 0644]
src/shared/ptyfwd.c
src/shared/seccomp-util.c
src/shared/tests.c
src/shared/tests.h
src/shared/udev-util.c
src/shared/uid-range.c
src/shared/user-record.c
src/shared/user-record.h
src/shared/varlink.c
src/shared/varlink.h
src/socket-proxy/socket-proxyd.c
src/systemctl/systemctl-add-dependency.c [new file with mode: 0644]
src/systemctl/systemctl-add-dependency.h [new file with mode: 0644]
src/systemctl/systemctl-cancel-job.c [new file with mode: 0644]
src/systemctl/systemctl-cancel-job.h [new file with mode: 0644]
src/systemctl/systemctl-clean-or-freeze.c [new file with mode: 0644]
src/systemctl/systemctl-clean-or-freeze.h [new file with mode: 0644]
src/systemctl/systemctl-compat-halt.c [new file with mode: 0644]
src/systemctl/systemctl-compat-halt.h [new file with mode: 0644]
src/systemctl/systemctl-compat-runlevel.c [new file with mode: 0644]
src/systemctl/systemctl-compat-runlevel.h [new file with mode: 0644]
src/systemctl/systemctl-compat-shutdown.c [new file with mode: 0644]
src/systemctl/systemctl-compat-shutdown.h [new file with mode: 0644]
src/systemctl/systemctl-compat-telinit.c [new file with mode: 0644]
src/systemctl/systemctl-compat-telinit.h [new file with mode: 0644]
src/systemctl/systemctl-daemon-reload.c [new file with mode: 0644]
src/systemctl/systemctl-daemon-reload.h [new file with mode: 0644]
src/systemctl/systemctl-edit.c [new file with mode: 0644]
src/systemctl/systemctl-edit.h [new file with mode: 0644]
src/systemctl/systemctl-enable.c [new file with mode: 0644]
src/systemctl/systemctl-enable.h [new file with mode: 0644]
src/systemctl/systemctl-is-active.c [new file with mode: 0644]
src/systemctl/systemctl-is-active.h [new file with mode: 0644]
src/systemctl/systemctl-is-enabled.c [new file with mode: 0644]
src/systemctl/systemctl-is-enabled.h [new file with mode: 0644]
src/systemctl/systemctl-is-system-running.c [new file with mode: 0644]
src/systemctl/systemctl-is-system-running.h [new file with mode: 0644]
src/systemctl/systemctl-kill.c [new file with mode: 0644]
src/systemctl/systemctl-kill.h [new file with mode: 0644]
src/systemctl/systemctl-list-dependencies.c [new file with mode: 0644]
src/systemctl/systemctl-list-dependencies.h [new file with mode: 0644]
src/systemctl/systemctl-list-jobs.c [new file with mode: 0644]
src/systemctl/systemctl-list-jobs.h [new file with mode: 0644]
src/systemctl/systemctl-list-machines.c [new file with mode: 0644]
src/systemctl/systemctl-list-machines.h [new file with mode: 0644]
src/systemctl/systemctl-list-unit-files.c [new file with mode: 0644]
src/systemctl/systemctl-list-unit-files.h [new file with mode: 0644]
src/systemctl/systemctl-list-units.c [new file with mode: 0644]
src/systemctl/systemctl-list-units.h [new file with mode: 0644]
src/systemctl/systemctl-log-setting.c [new file with mode: 0644]
src/systemctl/systemctl-log-setting.h [new file with mode: 0644]
src/systemctl/systemctl-logind.c [new file with mode: 0644]
src/systemctl/systemctl-logind.h [new file with mode: 0644]
src/systemctl/systemctl-preset-all.c [new file with mode: 0644]
src/systemctl/systemctl-preset-all.h [new file with mode: 0644]
src/systemctl/systemctl-reset-failed.c [new file with mode: 0644]
src/systemctl/systemctl-reset-failed.h [new file with mode: 0644]
src/systemctl/systemctl-service-watchdogs.c [new file with mode: 0644]
src/systemctl/systemctl-service-watchdogs.h [new file with mode: 0644]
src/systemctl/systemctl-set-default.c [new file with mode: 0644]
src/systemctl/systemctl-set-default.h [new file with mode: 0644]
src/systemctl/systemctl-set-environment.c [new file with mode: 0644]
src/systemctl/systemctl-set-environment.h [new file with mode: 0644]
src/systemctl/systemctl-set-property.c [new file with mode: 0644]
src/systemctl/systemctl-set-property.h [new file with mode: 0644]
src/systemctl/systemctl-show.c [new file with mode: 0644]
src/systemctl/systemctl-show.h [new file with mode: 0644]
src/systemctl/systemctl-start-special.c [new file with mode: 0644]
src/systemctl/systemctl-start-special.h [new file with mode: 0644]
src/systemctl/systemctl-start-unit.c [new file with mode: 0644]
src/systemctl/systemctl-start-unit.h [new file with mode: 0644]
src/systemctl/systemctl-switch-root.c [new file with mode: 0644]
src/systemctl/systemctl-switch-root.h [new file with mode: 0644]
src/systemctl/systemctl-sysv-compat.c [new file with mode: 0644]
src/systemctl/systemctl-sysv-compat.h [moved from src/systemctl/sysv-compat.h with 92% similarity]
src/systemctl/systemctl-trivial-method.c [new file with mode: 0644]
src/systemctl/systemctl-trivial-method.h [new file with mode: 0644]
src/systemctl/systemctl-util.c [new file with mode: 0644]
src/systemctl/systemctl-util.h [new file with mode: 0644]
src/systemctl/systemctl.c
src/systemctl/systemctl.h [new file with mode: 0644]
src/systemctl/sysv-compat.c [deleted file]
src/systemd/sd-event.h
src/systemd/sd-messages.h
src/systemd/sd-netlink.h
src/sysusers/sysusers.c
src/test/meson.build
src/test/test-condition.c
src/test/test-dns-domain.c
src/test/test-env-util.c
src/test/test-execute.c
src/test/test-fd-util.c
src/test/test-format-table.c
src/test/test-fstab-util.c
src/test/test-ipcrm.c
src/test/test-libudev.c
src/test/test-load-fragment.c
src/test/test-mountpoint-util.c
src/test/test-namespace.c
src/test/test-parse-util.c
src/test/test-path.c
src/test/test-psi-util.c [new file with mode: 0644]
src/test/test-strv.c
src/test/test-tables.c
src/test/test-user-record.c [new file with mode: 0644]
src/test/test-util.c
src/tmpfiles/tmpfiles.c
src/udev/net/link-config.c
src/udev/net/link-config.h
src/udev/scsi_id/scsi_id.c
src/udev/udev-builtin-keyboard.c
src/udev/udev-builtin-net_id.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/update-done/update-done.c
src/xdg-autostart-generator/xdg-autostart-service.c
src/xdg-autostart-generator/xdg-autostart-service.h
sysctl.d/50-coredump.conf.in
sysusers.d/meson.build
sysusers.d/systemd.conf.m4
test/README.testsuite
test/TEST-21-SYSUSERS/Makefile [deleted symlink]
test/TEST-21-SYSUSERS/test-10.expected-group [deleted file]
test/TEST-21-SYSUSERS/test-10.expected-passwd [deleted file]
test/TEST-21-SYSUSERS/test-14.expected-passwd [deleted file]
test/TEST-21-SYSUSERS/test-6.expected-group [deleted file]
test/TEST-21-SYSUSERS/test-6.expected-passwd [deleted file]
test/TEST-21-SYSUSERS/test-8.expected-passwd [deleted file]
test/TEST-21-SYSUSERS/test-9.expected-passwd [deleted file]
test/TEST-21-SYSUSERS/test.sh [deleted file]
test/TEST-29-UDEV-ID_RENAMING/test.sh
test/TEST-50-DISSECT/test.sh
test/fuzz/fuzz-catalog/systemd.pl.catalog
test/fuzz/fuzz-network-parser/directives.network
test/hwdb-test.sh
test/meson.build
test/test-network-generator-conversion.sh
test/test-network/conf/25-address-peer-ipv4.network [new file with mode: 0644]
test/test-network/conf/25-address-static.network
test/test-network/conf/25-route-static.network
test/test-network/conf/25-route-via-ipv6.network [new file with mode: 0644]
test/test-network/conf/25-sriov.network
test/test-network/conf/dhcp-client-gateway-ipv4.network
test/test-network/conf/dhcp-client-gateway-ipv6.network
test/test-network/conf/ipv6-prefix.network
test/test-network/conf/ipv6ra-prefix.network
test/test-network/systemd-networkd-tests.py
test/test-path/path-changed.service
test/test-path/path-directorynotempty.service
test/test-path/path-exists.service
test/test-path/path-existsglob.service
test/test-path/path-makedirectory.service
test/test-path/path-modified.service
test/test-path/path-mycustomunit.service
test/test-path/path-service.service [deleted file]
test/test-sysusers.sh.in [new file with mode: 0755]
test/test-sysusers/inline.expected-group [moved from test/TEST-21-SYSUSERS/inline.expected-group with 100% similarity]
test/test-sysusers/inline.expected-passwd [moved from test/TEST-21-SYSUSERS/inline.expected-passwd with 100% similarity]
test/test-sysusers/test-1.expected-group [moved from test/TEST-21-SYSUSERS/test-1.expected-group with 100% similarity]
test/test-sysusers/test-1.expected-passwd [moved from test/TEST-21-SYSUSERS/test-1.expected-passwd with 100% similarity]
test/test-sysusers/test-1.input [moved from test/TEST-21-SYSUSERS/test-1.input with 100% similarity]
test/test-sysusers/test-10.expected-group [new file with mode: 0644]
test/test-sysusers/test-10.expected-passwd [new file with mode: 0644]
test/test-sysusers/test-10.input [moved from test/TEST-21-SYSUSERS/test-10.input with 100% similarity]
test/test-sysusers/test-11.expected-group [moved from test/TEST-21-SYSUSERS/test-11.expected-group with 100% similarity]
test/test-sysusers/test-11.expected-passwd [moved from test/TEST-21-SYSUSERS/test-11.expected-passwd with 100% similarity]
test/test-sysusers/test-11.initial-group [moved from test/TEST-21-SYSUSERS/test-11.initial-group with 100% similarity]
test/test-sysusers/test-11.initial-passwd [moved from test/TEST-21-SYSUSERS/test-11.initial-passwd with 100% similarity]
test/test-sysusers/test-11.input [moved from test/TEST-21-SYSUSERS/test-11.input with 100% similarity]
test/test-sysusers/test-12.expected-group [moved from test/TEST-21-SYSUSERS/test-12.expected-group with 100% similarity]
test/test-sysusers/test-12.expected-passwd [moved from test/TEST-21-SYSUSERS/test-12.expected-passwd with 100% similarity]
test/test-sysusers/test-12.initial-group [moved from test/TEST-21-SYSUSERS/test-12.initial-group with 100% similarity]
test/test-sysusers/test-12.initial-passwd [moved from test/TEST-21-SYSUSERS/test-12.initial-passwd with 100% similarity]
test/test-sysusers/test-12.input [moved from test/TEST-21-SYSUSERS/test-12.input with 100% similarity]
test/test-sysusers/test-13.expected-group [moved from test/TEST-21-SYSUSERS/test-13.expected-group with 66% similarity]
test/test-sysusers/test-13.expected-passwd [moved from test/TEST-21-SYSUSERS/test-13.expected-passwd with 72% similarity]
test/test-sysusers/test-13.input [moved from test/TEST-21-SYSUSERS/test-13.input with 100% similarity]
test/test-sysusers/test-14.expected-group [moved from test/TEST-21-SYSUSERS/test-14.expected-group with 100% similarity]
test/test-sysusers/test-14.expected-passwd [new file with mode: 0644]
test/test-sysusers/test-14.initial-group [moved from test/TEST-21-SYSUSERS/test-14.initial-group with 100% similarity]
test/test-sysusers/test-14.input [moved from test/TEST-21-SYSUSERS/test-14.input with 100% similarity]
test/test-sysusers/test-2.expected-group [moved from test/TEST-21-SYSUSERS/test-2.expected-group with 57% similarity]
test/test-sysusers/test-2.expected-passwd [moved from test/TEST-21-SYSUSERS/test-2.expected-passwd with 61% similarity]
test/test-sysusers/test-2.input [moved from test/TEST-21-SYSUSERS/test-2.input with 81% similarity]
test/test-sysusers/test-3.expected-group [moved from test/TEST-21-SYSUSERS/test-3.expected-group with 100% similarity]
test/test-sysusers/test-3.expected-passwd [moved from test/TEST-21-SYSUSERS/test-3.expected-passwd with 100% similarity]
test/test-sysusers/test-3.input [moved from test/TEST-21-SYSUSERS/test-3.input with 100% similarity]
test/test-sysusers/test-4.expected-group [moved from test/TEST-21-SYSUSERS/test-4.expected-group with 100% similarity]
test/test-sysusers/test-4.expected-passwd [moved from test/TEST-21-SYSUSERS/test-4.expected-passwd with 100% similarity]
test/test-sysusers/test-4.input [moved from test/TEST-21-SYSUSERS/test-4.input with 100% similarity]
test/test-sysusers/test-5.expected-group [moved from test/TEST-21-SYSUSERS/test-5.expected-group with 100% similarity]
test/test-sysusers/test-5.expected-passwd [moved from test/TEST-21-SYSUSERS/test-5.expected-passwd with 100% similarity]
test/test-sysusers/test-5.input [moved from test/TEST-21-SYSUSERS/test-5.input with 100% similarity]
test/test-sysusers/test-6.expected-group [new file with mode: 0644]
test/test-sysusers/test-6.expected-passwd [new file with mode: 0644]
test/test-sysusers/test-6.input [moved from test/TEST-21-SYSUSERS/test-6.input with 100% similarity]
test/test-sysusers/test-7.expected-group [moved from test/TEST-21-SYSUSERS/test-7.expected-group with 100% similarity]
test/test-sysusers/test-7.expected-passwd [moved from test/TEST-21-SYSUSERS/test-7.expected-passwd with 100% similarity]
test/test-sysusers/test-7.input [moved from test/TEST-21-SYSUSERS/test-7.input with 100% similarity]
test/test-sysusers/test-8.expected-group [moved from test/TEST-21-SYSUSERS/test-8.expected-group with 100% similarity]
test/test-sysusers/test-8.expected-passwd [new file with mode: 0644]
test/test-sysusers/test-8.input [moved from test/TEST-21-SYSUSERS/test-8.input with 100% similarity]
test/test-sysusers/test-9.expected-group [moved from test/TEST-21-SYSUSERS/test-9.expected-group with 100% similarity]
test/test-sysusers/test-9.expected-passwd [new file with mode: 0644]
test/test-sysusers/test-9.input [moved from test/TEST-21-SYSUSERS/test-9.input with 100% similarity]
test/test-sysusers/unhappy-1.expected-err [moved from test/TEST-21-SYSUSERS/unhappy-1.expected-err with 100% similarity]
test/test-sysusers/unhappy-1.input [moved from test/TEST-21-SYSUSERS/unhappy-1.input with 100% similarity]
test/test-sysusers/unhappy-2.expected-err [moved from test/TEST-21-SYSUSERS/unhappy-2.expected-err with 100% similarity]
test/test-sysusers/unhappy-2.input [moved from test/TEST-21-SYSUSERS/unhappy-2.input with 100% similarity]
test/test-sysusers/unhappy-3.expected-err [moved from test/TEST-21-SYSUSERS/unhappy-3.expected-err with 100% similarity]
test/test-sysusers/unhappy-3.input [moved from test/TEST-21-SYSUSERS/unhappy-3.input with 100% similarity]
test/testsuite-04.units/forever-print-hola.service
test/testsuite-11.units/fail-on-restart.service
test/units/testsuite-16.service
test/units/testsuite-29.sh
test/units/testsuite-50.sh
tmpfiles.d/systemd-pstore.conf
tools/chromiumos/gen_autosuspend_rules.py
tools/make-autosuspend-rules.py
units/first-boot-complete.target [new file with mode: 0644]
units/initrd-cryptsetup.target [new file with mode: 0644]
units/meson.build
units/serial-getty@.service.m4
units/systemd-firstboot.service
units/systemd-homed-activate.service [new file with mode: 0644]
units/systemd-homed.service.in
units/systemd-hostnamed.service.in
units/systemd-importd.service.in
units/systemd-localed.service.in
units/systemd-logind.service.in
units/systemd-machine-id-commit.service
units/systemd-machined.service.in
units/systemd-oomd.service.in [new file with mode: 0644]
units/systemd-random-seed.service.in
units/systemd-resolved.service.in
units/systemd-timedated.service.in

index 1ca8228969ddc03b78d1a0684691d67f95235df2..5db53a4579012ebe281ffafd3f112baef6bba282 100644 (file)
@@ -5,7 +5,7 @@ about: A report of an error in a recent systemd version
 ---
 
 **systemd version the issue has been seen with**
-> ...
+ > …
 
 <!-- **NOTE:** Do not submit bug reports about anything but the two most recently released (non-rc) systemd versions upstream! -->
 <!-- See https://github.com/systemd/systemd/releases for the list of most recent releases. -->
@@ -14,6 +14,12 @@ about: A report of an error in a recent systemd version
 **Used distribution**
  > …
 
+**Linux kernel version used** (`uname -a`)
+ > …
+
+**CPU architecture issue was seen on**
+ > …
+
 **Expected behaviour you didn't see**
  > …
 
@@ -21,3 +27,4 @@ about: A report of an error in a recent systemd version
  > …
 
 **Steps to reproduce the problem**
+ > …
index 3b86689d27c02c6993524127377160e793cb6cfa..c9aec779c8b5608de73e94b1ace1893ce7a443ea 100644 (file)
@@ -13,13 +13,14 @@ on:
 
 jobs:
   build:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     strategy:
       fail-fast: false
       matrix:
         env:
           - { COMPILER: "gcc",   COMPILER_VERSION: "10" }
           - { COMPILER: "clang", COMPILER_VERSION: "10" }
+          - { COMPILER: "clang", COMPILER_VERSION: "11" }
     env: ${{ matrix.env }}
     steps:
       - name: Repository checkout
index 75fc36fffb10fcf1b5664e509d294a4bfa3bdcf3..0892e08dd1654b4788318303237fce5aca3112bf 100755 (executable)
@@ -19,7 +19,6 @@ PACKAGES=(
     expect
     fdisk
     gettext
-    iptables-dev
     iputils-ping
     isc-dhcp-client
     itstool
@@ -28,6 +27,7 @@ PACKAGES=(
     libcap-dev
     libcurl4-gnutls-dev
     libfdisk-dev
+    libfido2-dev
     libgpg-error-dev
     liblz4-dev
     liblzma-dev
@@ -38,6 +38,7 @@ PACKAGES=(
     libqrencode-dev
     libssl-dev
     libxkbcommon-dev
+    libxtables-dev
     libzstd-dev
     mount
     net-tools
diff --git a/NEWS b/NEWS
index 99194b02d0b068f3fd522eb9384925f510032881..843aefe7e3abd9d2490fe5d5d329723afe9bdb71 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,20 +2,21 @@ systemd System and Service Manager
 
 CHANGES WITH 247 in spe:
 
-        * KERNEL API INCOMPATIBILTY: Linux 4.12 introduced two new uevents
+        * KERNEL API INCOMPATIBILITY: Linux 4.12 introduced two new uevents
           "bind" and "unbind" to the Linux device model. When this kernel
           change was made, systemd-udevd was only minimally updated to handle
           and propagate these new event types. The introduction of these new
           uevents (which are typically generated for USB devices and devices
           needing a firmware upload before being functional) resulted in a
-          number of software issues, we so far didn't address (mostly because
-          there was hope the kernel maintainers would themeselves address these
-          issues in some form – which did not happen). To handle them properly,
-          many (if not most) udev rules files shipped in various packages need
-          updating, and so do many programs that monitor or enumerate devices
-          with libudev or sd-device, or otherwise process uevents. Please note
-          that this incompatibility is not fault of systemd or udev, but caused
-          by an incompatible kernel change that happened back in Linux 4.12.
+          number of issues which we so far didn't address. We hoped the kernel
+          maintainers would themselves address these issues in some form, but
+          that did not happen. To handle them properly, many (if not most) udev
+          rules files shipped in various packages need updating, and so do many
+          programs that monitor or enumerate devices with libudev or sd-device,
+          or otherwise process uevents. Please note that this incompatibility
+          is not fault of systemd or udev, but caused by an incompatible kernel
+          change that happened back in Linux 4.12, but is becoming more and
+          more visible as the new uevents are generated by more kernel drivers.
 
           To minimize issues resulting from this kernel change (but not avoid
           them entirely) starting with systemd-udevd 247 the udev "tags"
@@ -40,8 +41,8 @@ CHANGES WITH 247 in spe:
           device. To accommodate for this a new automatic property CURRENT_TAGS
           has been added that works similar to the existing TAGS property but
           only lists tags set by the most recent uevent/database
-          update. Similar, the libudev/sd-device API has been updated with new
-          functions to enumerate these 'current' tags, in addition to the
+          update. Similarly, the libudev/sd-device API has been updated with
+          new functions to enumerate these 'current' tags, in addition to the
           existing APIs that now enumerate the 'sticky' ones.
 
           To properly handle "bind"/"unbind" on Linux 4.12 and newer it is
@@ -53,12 +54,12 @@ CHANGES WITH 247 in spe:
             ACTION=="remove",GOTO="xyz_end" instead, so that the
             properties/tags they add are also applied whenever "bind" (or
             "unbind") is seen. (This is most important for all physical device
-            types — as that's for which "bind" and "unbind" are currently
-            usually generated, for all other device types this change is still
+            types — those for which "bind" and "unbind" are currently
+            generated, for all other device types this change is still
             recommended but not as important — but certainly prepares for
             future kernel uevent type additions).
 
-          • Similar, all code monitoring devices that contains an 'if' branch
+          • Similarly, all code monitoring devices that contains an 'if' branch
             discerning the "add" + "change" uevent actions from all other
             uevents actions (i.e. considering devices only relevant after "add"
             or "change", and irrelevant on all other events) should be reworked
@@ -74,8 +75,8 @@ CHANGES WITH 247 in spe:
           • Any code that uses device tags for deciding whether a device is
             relevant or not most likely needs to be updated to use the new
             udev_device_has_current_tag() API (or sd_device_has_current_tag()
-            in case sd-device is used), to check whether the tag is set
-            at the moment an uevent is seen (as opposed to the existing
+            in case sd-device is used), to check whether the tag is set at the
+            moment an uevent is seen (as opposed to the existing
             udev_device_has_tag() API which checks if the tag ever existed on
             the device, following the API concept redefinition explained
             above).
@@ -85,6 +86,12 @@ CHANGES WITH 247 in spe:
           this is not caused by systemd/udev changes, but result of a kernel
           behaviour change.
 
+        * The MountAPIVFS= service file setting now defaults to on if
+          RootImage= and RootDirectory= are used, which means that with those
+          two settings /proc/, /sys/ and /dev/ are automatically properly set
+          up for services. Previous behaviour may be restored by explicitly
+          setting MountAPIVFS=off.
+
         * Since PAM 1.2.0 (2015) configuration snippets may be placed in
           /usr/lib/pam.d/ in addition to /etc/pam.d/. If a file exists in the
           latter it takes precedence over the former, similar to how most of
@@ -97,9 +104,488 @@ CHANGES WITH 247 in spe:
           packages' vendor versions of their PAM stack definitions from
           /etc/pam.d/ to /usr/lib/pam.d/, but if such OS-wide migration is not
           desired the location to which systemd installs its PAM stack
-          configuration file may be changed via the "pamconfdir" meson variable
-          at build time, optionally undoing this change of default paths
-          introduced with systemd 247.
+          configuration may be changed via the -Dpamconfdir Meson option.
+
+        * The runtime dependencies on libqrencode, libpcre2, libidn/libidn2,
+          libpwquality and libcryptsetup have been changed to be based on
+          dlopen(): instead of regular dynamic library dependencies declared in
+          the binary ELF headers, these libraries are now loaded on demand
+          only, if they are available. If the libraries cannot be found the
+          relevant operations will fail gracefully, or a suitable fallback
+          logic is chosen. This is supposed to be useful for general purpose
+          distributions, as it allows minimizing the list of dependencies the
+          systemd packages pull in, permitting building of more minimal OS
+          images, while still making use of these "weak" dependencies should
+          they be installed. Since many package managers automatically
+          synthesize package dependencies from ELF shared library dependencies,
+          some additional manual packaging work has to be done now to replace
+          those (slightly downgraded from "required" to "recommended" or
+          whatever is conceptually suitable for the package manager). Note that
+          this change does not alter build-time behaviour: as before the
+          build-time dependencies have to be installed during build, even if
+          they now are optional during runtime.
+
+        * sd-event.h gained a new call sd_event_add_time_relative() for
+          installing timers relative to the current time. This is mostly a
+          convenience wrapper around the pre-existing sd_event_add_time() call
+          which installs absolute timers.
+
+        * sd-event event sources may now be placed in a new "exit-on-failure"
+          mode, which may be controlled via the new
+          sd_event_source_get_exit_on_failure() and
+          sd_event_source_set_exit_on_failure() functions. If enabled, any
+          failure returned by the event source handler functions will result in
+          exiting the event loop (unlike the default behaviour of just
+          disabling the event source but continuing with the event loop). This
+          feature is useful to set for all event sources that define "primary"
+          program behaviour (where failure should be fatal) in contrast to
+          "auxiliary" behaviour (where failure should remain local).
+
+        * Most event source types sd-event supports now accept a NULL handler
+          function, in which case the event loop is exited once the event
+          source is to be dispatched, using the userdata pointer — converted to
+          a signed integer — as exit code of the event loop. Previously this
+          was supported for IO and signal event sources already. Exit event
+          sources still do not support this (simply because it makes little
+          sense there, as the event loop is already exiting when they are
+          dispatched).
+
+        * A new per-unit setting RootImageOptions= has been added which allows
+          tweaking the mount options for any file system mounted as effect of
+          the RootImage= setting.
+
+        * Another new per-unit setting MountImages= has been added, that allows
+          mounting additional disk images into the file system tree accessible
+          to the service.
+
+        * systemd-repart now generates JSON output when requested with the new
+          --json= switch.
+
+        * systemd-machined's OpenMachineShell() bus call will now pass
+          additional policy metadata data fields to the PolicyKit
+          authentication request.
+
+        * systemd-tmpfiles gained a new -E switch, which is equivalent to
+          --exclude-prefix=/dev --exclude-prefix=/proc --exclude=/run
+          --exclude=/sys. It's particularly useful in combination with --root=,
+          when operating on OS trees that do not have any of these four runtime
+          directories mounted, as this means no files below these subtrees are
+          created or modified, since those mount points should probably remain
+          empty.
+
+        * systemd-tmpfiles gained a new --image= switch which is like --root=,
+          but takes a disk image instead of a directory as argument. The
+          specified disk image is mounted inside a temporary mount namespace
+          and the tmpfiles.d/ drop-ins stored in the image are executed and
+          applied to the image. systemd-sysusers similarly gained a new
+          --image= switch, that allows the sysusers.d/ drop-ins stored in the
+          image to be applied onto the image.
+
+        * Similarly, the journalctl command also gained an --image= switch,
+          which is a quick one-step solution to look at the log data included
+          in OS disk images.
+
+        * journalctl's --output=cat option (which outputs the log content
+          without any metadata, just the pure text messages) will now make use
+          of terminal colors when run on a suitable terminal, similarly to the
+          other output modes.
+
+        * JSON group records now support a "description" string that may be
+          used to add a human-readable textual description to such groups. This
+          is supposed to match the user's GECOS field which traditionally
+          didn't have a counterpart for group records.
+
+        * The "systemd-dissect" tool that may be used to inspect OS disk images
+          and that was previously installed to /usr/lib/systemd/ has now been
+          moved to /usr/bin/, reflecting its updated status of an officially
+          supported tool with a stable interface. It gained support for a new
+          --mkdir switch which when combined with --mount has the effect of
+          creating the directory to mount the image to if it is missing
+          first. It also gained two new commands --copy-from and --copy-to for
+          copying files and directories in and out of an OS image without the
+          need to manually mount it. It also acquired support for a new option
+          --json= to generate JSON output when inspecting an OS image.
+
+        * The cgroup2 file system is now mounted with the
+          "memory_recursiveprot" mount option, supported since kernel 5.7. This
+          means that the MemoryLow= and MemoryMin= unit file settings now apply
+          recursively to whole subtrees.
+
+        * systemd-homed now defaults to using the btrfs file system — if
+          available — when creating home directories in LUKS volumes. This may
+          be changed with the DefaultFileSystemType= setting in homed.conf.
+          It's now the default file system in various major distributions and
+          has the major benefit for homed that it can be grown and shrunk while
+          mounted, unlike the other contenders ext4 and xfs, which can both be
+          grown online, but not shrunk (in fact xfs is the technically most
+          limited option here, as it cannot be shrunk at all).
+
+        * JSON user records managed by systemd-homed gained support for
+          "recovery keys". These are basically secondary passphrases that can
+          unlock user accounts/home directories. They are computer-generated
+          rather than user-chosen, and typically have greater entropy.
+          homectl's --recovery-key= option may be used to add a recovery key to
+          a user account. The generated recovery key is displayed as a QR code,
+          so that it can be scanned to be kept in a safe place. This feature is
+          particularly useful in combination with systemd-homed's support for
+          FIDO2 or PKCS#11 authentication, as a secure fallback in case the
+          security tokens are lost. Recovery keys may be entered wherever the
+          system asks for a password.
+
+        * systemd-homed now maintains a "dirty" flag for each LUKS encrypted
+          home directory which indicates that a home directory has not been
+          deactivated cleanly when offline. This flag is useful to identify
+          home directories for which the offline discard logic did not run when
+          offlining, and where it would be a good idea to log in again to catch
+          up.
+
+        * systemctl gained a new parameter --timestamp= which may be used to
+          change the style in which timestamps are output, i.e. whether to show
+          them in local timezone or UTC, or whether to show µs granularity.
+
+        * Alibaba's "pouch" container manager is now detected by
+          systemd-detect-virt, ConditionVirtualization= and similar
+          constructs. Similar, they now also recognize IBM PowerVM machine
+          virtualization.
+
+        * systemd-nspawn has been reworked to use the /run/host/incoming/ as
+          place to use for propagating external mounts into the
+          container. Similarly /run/host/notify is now used as the socket path
+          for container payloads to communicate with the container manager
+          using sd_notify(). The container manager now uses the
+          /run/host/inaccessible/ directory to place "inaccessible" file nodes
+          of all relevant types which may be used by the container payload as
+          bind mount source to over-mount inodes to make them inaccessible.
+          /run/host/container-manager will now be initialized with the same
+          string as the $container environment variable passed to the
+          container's PID 1. /run/host/container-uuid will be initialized with
+          the same string as $container_uuid. This means the /run/host/
+          hierarchy is now the primary way to make host resources available to
+          the container. The Container Interface documents these new files and
+          directories:
+
+          https://systemd.io/CONTAINER_INTERFACE
+
+        * Support for the "ConditionNull=" unit file condition has been
+          deprecated and undocumented for 6 years. systemd started to warn
+          about its use 1.5 years ago. It has now been removed entirely.
+
+        * sd-bus.h gained a new API call sd_bus_error_has_names(), which takes
+          a sd_bus_error struct and a list of error names, and checks if the
+          error matches one of these names. It's a convenience wrapper that is
+          useful in cases where multiple errors shall be handled the same way.
+
+        * A new system call filter list "@known" has been added, that contains
+          all system calls known at the time systemd was built.
+
+        * Behaviour of system call filter allow lists has changed slightly:
+          system calls that are contained in @known will result in a EPERM by
+          default, while those not contained in it result in ENOSYS. This
+          should improve compatibility because known system calls will thus be
+          communicated as prohibited, while unknown (and thus newer ones) will
+          be communicated as not implemented, which hopefully has the greatest
+          chance of triggering the right fallback code paths in client
+          applications.
+
+        * "systemd-analyze syscall-filter" will now show two separate sections
+          at the bottom of the output: system calls known during systemd build
+          time but not included in any of the filter groups shown above, and
+          system calls defined on the local kernel but known during systemd
+          build time.
+
+        * If the $SYSTEMD_LOG_SECCOMP=1 environment variable is set for
+          systemd-nspawn all system call filter violations will be logged by
+          the kernel (audit). This is useful for tracking down system calls
+          invoked by container payloads that are prohibited by the container's
+          system call filter policy.
+
+        * Two new unit file settings ProtectProc= and ProcSubset= have been
+          added that expose the hidepid= and subset= mount options of procfs.
+          All processes of the unit will only see processes in /proc that are
+          are owned by the unit's user. This is an important new sandboxing
+          option that is recommended to be set on all system services. All
+          long-running system services that are included in systemd itself set
+          this option now. This option is only supported on kernel 5.8 and
+          above, since the hidepid= option supported on older kernels was not a
+          per-mount option but actually applied to the whole PID namespace.
+
+        * Socket units gained a new boolean setting FlushPending=. If enabled
+          all pending socket data/connections are flushed whenever the socket
+          unit enters the "listening" state, i.e. after the associated service
+          exited.
+
+        * The unit file setting NUMAMask= gained a new "all" value: when used,
+          all existing NUMA nodes are added to the NUMA mask.
+
+        * A new "credentials" logic has been added to system services. This is
+          a simple mechanism to pass privileged data to services in a safe and
+          secure way. It's supposed to be used to pass per-service secret data
+          such as passwords or cryptographic keys but also associated less
+          private information such as user names, certificates, and similar to
+          system services. Each credential is identified by a short user-chosen
+          name and may contain arbitrary binary data. Two new unit file
+          settings have been added: SetCredential= and LoadCredential=. The
+          former allows setting a credential to a literal string, the latter
+          sets a credential to the contents of a file (or data read from a
+          user-chosen AF_UNIX stream socket). Credentials are passed to the
+          service via a special credentials directory, one file for each
+          credential. The path to the credentials directory is passed in a new
+          $CREDENTIALS_DIRECTORY environment variable. Since the credentials
+          are passed in the file system they may be easily referenced in
+          ExecStart= command lines too, thus no explicit support for the
+          credentials logic in daemons is required (though ideally daemons
+          would look for the bits they need in $CREDENTIALS_DIRECTORY
+          themselves automatically, if set). The $CREDENTIALS_DIRECTORY is
+          backed by unswappable memory if privileges allow it, immutable if
+          privileges allow it, is accessible only to the service's UID, and is
+          automatically destroyed when the service stops.
+
+        * systemd-nspawn supports the same credentials logic. It can both
+          consume credentials passed to it via the aforementioned
+          $CREDENTIALS_DIRECTORY protocol as well as pass these credentials on
+          to its payload. The service manager/PID 1 has been updated to match
+          this: it can also accept credentials from the container manager that
+          invokes it (in fact: any process that invokes it), and passes them on
+          to its services. Thus, credentials can be propagated recursively down
+          the tree: from a system's service manager to a systemd-nspawn
+          service, to the service manager that runs as container payload and to
+          the service it runs below. Credentials may also be added on the
+          systemd-nspawn command line, using new --set-credential= and
+          --load-credential= command line switches that match the
+          aforementioned service settings.
+
+        * systemd-repart gained new settings Format=, Encrypt=, CopyFiles= in
+          the partition drop-ins which may be used to format/LUKS
+          encrypt/populate any created partitions. The partitions are
+          encrypted/formatted/populated before they are registered in the
+          partition table, so that they appear atomically: either the
+          partitions do not exist yet or they exist fully encrypted, formatted,
+          and populated — there is no time window where they are
+          "half-initialized". Thus the system is robust to abrupt shutdown: if
+          the tool is terminated half-way during its operations on next boot it
+          will start from the beginning.
+
+        * systemd-repart's --size= operation gained a new "auto" value. If
+          specified, and operating on a loopback file it is automatically sized
+          to the minimal size the size constraints permit. This is useful to
+          use "systemd-repart" as an image builder for minimally sized images.
+
+        * systemd-resolved now gained a third IPC interface for requesting name
+          resolution: besides D-Bus and local DNS to 127.0.0.53 a Varlink
+          interface is now supported. The nss-resolve NSS module has been
+          modified to use this new interface instead of D-Bus. Using Varlink
+          has a major benefit over D-Bus: it works without a broker service,
+          and thus already during earliest boot, before the dbus daemon has
+          been started. This means name resolution via systemd-resolved now
+          works at the same time systemd-networkd operates: from earliest boot
+          on, including in the initrd.
+
+        * systemd-resolved gained support for a new DNSStubListenerExtra=
+          configuration file setting which may be used to specify additional IP
+          addresses the built-in DNS stub shall listen on, in addition to the
+          main one on 127.0.0.53:53.
+
+        * Name lookups issued via systemd-resolved's D-Bus and Varlink
+          interfaces (and thus also via glibc NSS if nss-resolve is used) will
+          now honour a trailing dot in the hostname: if specified the search
+          path logic is turned off. Thus "resolvectl query foo." is now
+          equivalent to "resolvectl query --search=off foo.".
+
+        * systemd-resolved gained a new D-Bus property "ResolvConfMode" that
+          exposes how /etc/resolv.conf is currently managed: by resolved (and
+          in which mode if so) or another subsystem. "resolvctl" will display
+          this property in its status output.
+
+        * The resolv.conf snippets systemd-resolved provides will now set "."
+          as the search domain if no other search domain is known. This turns
+          off the derivation of an implicit search domain by nss-dns for the
+          hostname, when the hostname is set to an FQDN. This change is done to
+          make nss-dns using resolv.conf provided by systemd-resolved behave
+          more similarly to nss-resolve.
+
+        * systemd-tmpfiles' file "aging" logic (i.e. the automatic clean-up of
+          /tmp/ and /var/tmp/ based on file timestamps) now looks at the
+          "birth" time (btime) of a file in addition to the atime, mtime, and
+          ctime.
+
+        * systemd-analyze gained a new verb "capability" that lists all known
+          capabilities by the systemd build and by the kernel.
+
+        * If a file /usr/lib/clock-epoch exists, PID 1 will read its mtime and
+          advance the system clock to it at boot if it is noticed to be before
+          that time. Previously, PID 1 would only advance the time to an epoch
+          time that is set during build-time. With this new file OS builders
+          can change this epoch timestamp on individual OS images without
+          having to rebuild systemd.
+
+        * systemd-logind will now listen to the KEY_RESTART key from the Linux
+          input layer and reboot the system if it is pressed, similarly to how
+          it already handles KEY_POWER, KEY_SUSPEND or KEY_SLEEP. KEY_RESTART
+          was originally defined in the Multimedia context (to restart playback
+          of a song or film), but is now primarily used in various embedded
+          devices for "Reboot" buttons. Accordingly, systemd-logind will now
+          honour it as such. This may configured in more detail via the new
+          HandleRebootKey= and RebootKeyIgnoreInhibited=.
+
+        * systemd-nspawn/systemd-machined will now reconstruct hardlinks when
+          copying OS trees, for example in "systemd-nspawn --ephemeral",
+          "systemd-nspawn --template=", "machinectl clone" and similar. This is
+          useful when operating with OSTree images, which use hardlinks heavily
+          throughout, and where such copies previously resulting in "exploding"
+          hardlinks.
+
+        * systemd-nspawn's --console= setting gained support for a new
+          "autopipe" value, which is identical to "interactive" when invoked on
+          a TTY, and "pipe" otherwise.
+
+        * systemd-networkd's .network files gained support for explicitly
+          configuring the multicast membership entries of bridge devices in the
+          [BridgeMDB] section. It also gained support for the PIE queuing
+          discipline in the [FlowQueuePIE] sections.
+
+        * systemd-networkd's .netdev files may now be used to create "BareUDP"
+          tunnels, configured in the new [BareUDP] setting. VXLAN tunnels may
+          now be marked to be independent of any underlying network interface
+          via the new Independent= boolean setting.
+
+        * systemd-networkd's Gateway= setting in .network files now accepts the
+          special values _dhcp4 and _ipv6ra to configure additional, locally
+          defined, explicit routes to the gateway acquired via DHCP or IPv6
+          Router Advertisements.
+
+        * systemctl gained support for two new verbs: "service-log-level" and
+          "service-log-target" may be used on services that implement the
+          generic org.freedesktop.LogControl1 D-Bus interface to dynamically
+          adjust the log level and target. All of systemd's long-running
+          services support this now, but ideally all system services would
+          implement this interface to make the system more uniformly
+          debuggable.
+
+        * The SystemCallErrorNumber= unit file setting now accepts the new
+          "kill" and "log" actions, in addition to arbitrary error number
+          specifications as before. If "kill" the the processes are killed on
+          the event, if "log" the offending system call is audit logged.
+
+        * A new SystemCallLog= unit file setting has been added that accepts a
+          list of system calls that shall be logged about (audit).
+
+        * The OS image dissection logic (as used by RootImage= in unit files or
+          systemd-nspawn's --image= switch) has gained support for identifying
+          and mounting explicit /usr/ partitions, which are now defined in the
+          discoverable partition specification. This should be useful for
+          environments where the root file system is
+          generated/formatted/populated dynamically on first boot and combined
+          with an immutable /usr/ tree that is supplied by the vendor.
+
+        * In the final phase of shutdown, within the systemd-shutdown binary
+          we'll now try to detach MD devices (i.e software RAID) in addition to
+          loopback block devices and DM devices as before. This is supposed to
+          be a safety net only, in order to increase robustness if things go
+          wrong. Storage subsystems are expected to properly detach their
+          storage volumes during regular shutdown already (or in case of
+          storage backing the root file system: in the initrd hook we return to
+          later).
+
+        * If the SYSTEMD_LOG_TID environment variable is set all systemd tools
+          will now log the thread ID in their log output. This is useful when
+          working with heavily threaded programs.
+
+        * If the SYSTEMD_RDRAND environment variable is set to "0", systemd will
+          not use the RDRAND CPU instruction. This is useful in environments
+          such as replay debuggers where non-deterministic behaviour is not
+          desirable.
+
+        * The autopaging logic in systemd's various tools (such as systemctl)
+          has been updated to turn on "secure" mode in "less"
+          (i.e. $LESSECURE=1) if execution in a "sudo" environment is
+          detected. This disables invoking external programs from the pager,
+          via the pipe logic. This behaviour may be overridden via the new
+          $SYSTEMD_PAGERSECURE environment variable.
+
+        * Units which have resource limits (.service, .mount, .swap, .slice,
+          .socket, and .slice) gained new configuration settings
+          ManagedOOMSwap=, ManagedOOMMemoryPressure=, and
+          ManagedOOMMemoryPressureLimitPercent= that specify resource pressure
+          limits and optional action taken by systemd-oomd.
+
+        * A new service systemd-oomd has been added. It monitors resource
+          contention for selected parts of the unit hierarchy using the PSI
+          information reported by the kernel, and kills processes when memory
+          or swap pressure is above configured limits. This service is only
+          enabled in developer mode (see below) and should be considered a
+          preview in this release. Behaviour details and option names are
+          subject to change without the usual backwards-compatibility promises.
+
+        * A new helper oomctl has been added to introspect systemd-oomd state.
+          If also is only available in developer mode and should be considered
+          a preview without the usual backwards-compatibility promises.
+
+        * New meson option -Dcompat-mutable-uid-boundaries= has been added. If
+          enabled, systemd reads the system UID boundaries from /etc/login.defs
+          at runtime, instead of using the built-in values selected during
+          build. This is an option to improve compatibility for upgrades from
+          old systems. It's strongly recommended not to make use of this
+          functionality on new systems (or even enable it during build), as it
+          makes something runtime-configurable that is mostly an implementation
+          detail of the OS, and permits avoidable differences in deployments
+          that create all kinds of problems in the long run.
+
+        * New meson option '-Dmode=developer|release' has been added. When
+          'developer', additional checks and features are enabled that are
+          relevant during upstream development, e.g. verification that
+          semi-automatically-generated documentation has been properly updated
+          following API changes. Those checks are considered hints for
+          developers and are not actionable in downstream builds. In addition,
+          extra features that are not ready for general consumption may be
+          enabled in developer mode. It is thus recommended to set
+          '-Dmode=release' in end-user and distro builds.
+
+        * systemd-cryptsetup gained support for processing detached LUKS
+          headers specified on the kernel command line via the header=
+          parameter of the luks.options= kernel command line option. The same
+          device/path syntax as for key files is supported for header files
+          like this.
+
+        * The "net_id" built-in of udev has been updated to ignore ACPI _SUN
+          slot index data for devices that are connected through a PCI bridge
+          where the _SUN index is associated with the bridge instead of the
+          network device itself. Previously this would create ambiguous device
+          naming if multiple network interfaces were connected to the same PCI
+          bridge. Since this is a naming scheme incompatibility on systems that
+          possess hardware like this it has been introduced as new naming
+          scheme "v247". The previous scheme can be selected via the
+          "net.naming-scheme=v245" kernel command line parameter.
+
+        * ConditionFirstBoot= semantics have been modified to be safe towards
+          abnormal system power-off during first boot. Specifically, the
+          "systemd-machine-id-commit.service" service now acts as boot
+          milestone indicating when the first boot process is sufficiently
+          complete in order to not consider the next following boot also a
+          first boot. If the system is reset before this unit is reached the
+          first time, the next boot will still be considered a first boot; once
+          it has been reached, no further boots will be considered a first
+          boot. The "first-boot-complete.target" unit now acts as official hook
+          point to order against this. If a service shall be run on every boot
+          until the first boot fully succeeds it may thus be ordered before
+          this target unit (and pull it in) and carry ConditionFirstBoot=
+          appropriately.
+
+        * bootctl's set-default and set-oneshot commands now accept the three
+          special strings "@default", "@oneshot", "@current" in place of a boot
+          entry id. These strings are resolved to the current default and
+          oneshot boot loader entry, as well as the currently booted one. Thus
+          a command "bootctl set-default @current" may be used to make the
+          currently boot menu item the new default for all subsequent boots.
+
+        * A new generic target unit "initrd-cryptsetup.target" has been added
+          that is supposed to pull in all encrypted volumes that shall be set
+          up during the initrd phase. It takes the place of "cryptsetup.target"
+          and "remote-cryptsetup.target" that exist during the host boot
+          phase. In other words, the new "initrd-cryptsetup.target" is supposed
+          to take the role for "initrd-fs.target", but for encrypted volumes.
+
+        * "systemctl edit" has been updated to show the original effective unit
+          contents in commented form in the text editor.
 
 CHANGES WITH 246:
 
index f836d812b18c0672a332632a88d8ab251e6723ec..e8703ea6effdeb8d1412303c471bad69b03df38e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -11,7 +11,9 @@ System and Service Manager
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
 [![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/)<br/>
+[![CentOS CI - CentOS 7](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20CentOS%207&job=upstream-centos7)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-centos7/)<br/>
+[![CentOS CI - Arch](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20Arch&job=upstream-vagrant-archlinux)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux/)<br/>
+[![CentOS CI - Arch (sanitizers)](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20Arch%20(sanitizers)&job=upstream-vagrant-archlinux-sanitizers)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux-sanitizers/)<br/>
 [![Build Status](https://dev.azure.com/evvers/systemd-systemd/_apis/build/status/systemd.systemd?branchName=master)](https://dev.azure.com/evvers/systemd-systemd/_build/latest?definitionId=1&branchName=master)<br/>
 [![Fossies codespell report](https://fossies.org/linux/test/systemd-master.tar.gz/codespell.svg)](https://fossies.org/linux/test/systemd-master.tar.gz/codespell.html)</br>
 [![Packaging status](https://repology.org/badge/tiny-repos/systemd.svg)](https://repology.org/project/systemd/versions)
diff --git a/TODO b/TODO
index f19fdcc56bf1bc08e5925337dfcf03c40348e6a8..c6c00a5e9bc4a1f4fecf1424eb52ea8fbc010ea6 100644 (file)
--- a/TODO
+++ b/TODO
@@ -20,6 +20,15 @@ Janitorial Clean-ups:
 
 Features:
 
+* systemd-analyze netif that explains predictable interface (or networkctl)
+
+* port selinux code from mallinfo() to mallinfo2() once added to glibc
+
+* Add service setting to run a service within the specified VRF. i.e. do the
+  equivalent of "ip vrf exec".
+
+* export action of device object on sd-device, so that monitor becomes useful
+
 * add root=tmpfs that mounts a tmpfs to /sysroot (to be used in combination
   with usr=…, for a similar effect as systemd.volatile=yes but without the
   "hide-out" effect). Also, add root=gpt-auto-late support or so, that is like
@@ -97,7 +106,6 @@ Features:
 
 * make us use dynamically fewer deps for containers in general purpose distros:
   o turn into dlopen() deps:
-    - libidn2 (always)
     - elfutils (always)
     - p11-kit-trust (always)
     - kmod-libs (only when called from PID 1)
@@ -805,9 +813,6 @@ Features:
 
 * systemctl: if some operation fails, show log output?
 
-* systemctl edit: use equivalent of cat() to insert existing config as a comment, prepended with #.
-  Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc.
-
 * exponential backoff in timesyncd when we cannot reach a server
 
 * timesyncd: add ugly bus calls to set NTP servers per-interface, for usage by NM
index c5786c4012d4ae2c71cc7794f19b99f77dfdbc8a..f8816c7601e318a7bcfe4d3fa093a559b8c48c77 100644 (file)
@@ -78,7 +78,7 @@ Documentation: man:core(5)
 Subject: Новая сесія № @SESSION_ID@ створана для карыстальніка @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Новая сесія з № @SESSION_ID@ створана для карыстальніка @USER_ID@.
 
@@ -88,7 +88,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Сесія № @SESSION_ID@ спынена
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Сесія № @SESSION_ID@ спынена.
 
@@ -96,7 +96,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Даступна новае працоўнае месца № @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Новае працоўнае месца № @SEAT_ID@ наладжана і даступна для выкарыстання.
 
@@ -104,7 +104,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Працоўнае месца № @SEAT_ID@ выдалена
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Працоўнае месца № @SEAT_ID@ выдалена і больш не даступна.
 
index bec5c6f0487a491331d15caa1fb2dad98cf26e73..ef9682c9b543c2ca469e25b004de864b2507d7a7 100644 (file)
@@ -79,7 +79,7 @@ Rekamiendujecca paviedamić ab hetym raspracoŭnikam.
 Subject: Novaja siesija № @SESSION_ID@ stvorana dlia karystaĺnika @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Novaja siesija z № @SESSION_ID@ stvorana dlia karystaĺnika @USER_ID@.
 
@@ -89,7 +89,7 @@ Lidar hetaj siesii pad № @LEADER@.
 Subject: Siesija № @SESSION_ID@ spyniena
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Siesija № @SESSION_ID@ spyniena.
 
@@ -97,7 +97,7 @@ Siesija № @SESSION_ID@ spyniena.
 Subject: Dastupna novaje pracoŭnaje miesca № @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Novaje pracoŭnaje miesca № @SEAT_ID@ naladžana i dastupna dlia
 vykarystannia.
@@ -106,7 +106,7 @@ vykarystannia.
 Subject: Pracoŭnaje miesca № @SEAT_ID@ vydaliena
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Pracoŭnaje miesca № @SEAT_ID@ vydaliena i boĺš nie dastupna.
 
index 41f7b21bce26a412ba75524610fd75b8f71c4b8e..fcb245c154de7330ec566353be37943ed5127b47 100644 (file)
@@ -81,7 +81,7 @@ Documentation: man:core(5)
 Subject: Създадена е нова сесия № @SESSION_ID@ за потребителя „@USER_ID@“
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 За потребителя „@USER_ID@“ е създадена нова сесия № @SESSION_ID@.
 
@@ -91,7 +91,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Сесия № @SESSION_ID@ приключи
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Сесия № @SESSION_ID@ приключи работа.
 
@@ -99,7 +99,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Налично е ново работно място № @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Новото работно място № @SEAT_ID@ е настроено и готово за работа.
 
@@ -107,7 +107,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Работното място № @SEAT_ID@ е премахнато
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Работното място № @SEAT_ID@ вече не е налично.
 
index 056df00de8fb8e938de7bb674521c8f33abea625..3ad20e04ce35a4b6f264e1b746b1fb8b423e469e 100644 (file)
@@ -89,7 +89,7 @@ about the file being truncated.
 Subject: A new session @SESSION_ID@ has been created for user @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A new session with the ID @SESSION_ID@ has been created for the user @USER_ID@.
 
@@ -99,7 +99,7 @@ The leading process of the session is @LEADER@.
 Subject: Session @SESSION_ID@ has been terminated
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A session with the ID @SESSION_ID@ has been terminated.
 
@@ -107,7 +107,7 @@ A session with the ID @SESSION_ID@ has been terminated.
 Subject: A new seat @SEAT_ID@ is now available
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A new seat @SEAT_ID@ has been configured and is now available.
 
@@ -115,7 +115,7 @@ A new seat @SEAT_ID@ has been configured and is now available.
 Subject: Seat @SEAT_ID@ has now been removed
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A seat @SEAT_ID@ has been removed and is no longer available.
 
index aecfafa05f156a865241d2cf8af8038562dfed27..eed98fa18dc35181cde8243a1650a97a56edc00b 100644 (file)
@@ -64,7 +64,7 @@ og burde blive reporteret som en bug til folkene bag
 Subject: En ny session @SESSION_ID@ er blevet lavet for bruger @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 En ny session med ID @SESSION_ID@ er blevet lavet for brugeren @USER_ID@.
 
@@ -74,7 +74,7 @@ Den ledende process for sessionen er @LEADER@.
 Subject: Session @SESSION_ID@ er blevet lukket ned
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 En session med ID @SESSION_ID@ er blevet lukket ned.
 
@@ -82,7 +82,7 @@ En session med ID @SESSION_ID@ er blevet lukket ned.
 Subject: En ny arbejdsstation $SEAT_ID@ er nu tilgængelig
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig.
 
@@ -90,7 +90,7 @@ En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig.
 Subject: Arbejdsstation @SEAT_ID@ er nu blevet fjernet
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 En arbejdsstation @SEAT_ID@ er blevet fjernet og er ikke længere tilgængelig.
 
index 13edd083cbacfb83c083826d4a6eed47aafaa8b6..c2319b8228dc6996efcaf28958857a17c2230632 100644 (file)
@@ -82,7 +82,7 @@ incriminé, et cela devrait être notifié à son concepteur comme un défaut (b
 Subject: Une nouvelle session @SESSION_ID@ a été créée pour l'utilisateur @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Une nouvelle session a été créée pour l'utilisateur @USER_ID@ avec
 l'identifiant (ID) @SESSION_ID@.
@@ -93,7 +93,7 @@ Le processus maître de la session est @LEADER@.
 Subject: La session @SESSION_ID@ s'est terminée
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 La session d'identifiant (ID) @SESSION_ID@ s'est terminée.
 
@@ -101,7 +101,7 @@ La session d'identifiant (ID) @SESSION_ID@ s'est terminée.
 Subject: Un nouveau poste (seat) @SEAT_ID@ est disponible
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Un nouveau poste (seat) @SEAT_ID@ a été configuré et est maintenant
 disponible.
@@ -110,7 +110,7 @@ disponible.
 Subject: Le poste (seat) @SEAT_ID@ a été retiré
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Le poste (seat) @SEAT_ID@ a été retiré et n'est plus disponible.
 
index 40727abaf54a3b05da47314c144049116f6d1297..43d69623cdd0b93bd84de8083a4b717d8772f52e 100644 (file)
@@ -78,7 +78,7 @@ trebalo bi se prijaviti razvijatelju kao greška.
 Subject: Nova sesija @SESSION_ID@ je stvorena za korisnika @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Nova sesija sa ID @SESSION_ID@ je stvorena za korisnika @USER_ID@.
 
@@ -88,7 +88,7 @@ Glavni proces sesije je @LEADER@.
 Subject: Sesija @SESSION_ID@ je prekinuta
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Sesija sa ID @SESSION_ID@ je prekinuta.
 
@@ -96,7 +96,7 @@ Sesija sa ID @SESSION_ID@ je prekinuta.
 Subject: Novo sjedište @SEAT_ID@ je sada dostupno
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Novo sjedište @SEAT_ID@ je podešeno i sada je dostupno.
 
@@ -104,7 +104,7 @@ Novo sjedište @SEAT_ID@ je podešeno i sada je dostupno.
 Subject: Sjedište @SEAT_ID@ je sada uklonjeno
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Sjedište @SEAT_ID@ je uklonjeno i više nije dostupno.
 
index 5565b80b2a10197a7dffd3be77cd1211d1b7b6f0..ea60af20b2e8e80f7ea0dd7f161efecb3e33360b 100644 (file)
@@ -64,7 +64,7 @@ a szállítója felé kell bejelenteni.
 Subject: Új munkamenet (@SESSION_ID@) létrehozva, felhasználója: @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Létrejött egy új munkamenet @SESSION_ID@ azonosítóval ezen felhasználóhoz:
 @USER_ID@.
@@ -75,7 +75,7 @@ A munkamenet vezető folyamata: @LEADER@.
 Subject: Munkamenet (@SESSION_ID@) befejezve
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A következő azonosítójú munkamenet befejeződött: @SESSION_ID@.
 
@@ -83,7 +83,7 @@ A következő azonosítójú munkamenet befejeződött: @SESSION_ID@.
 Subject: Elérhető egy új munkaállomás: @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Beállításra kerül és használható egy új munkaállomás: @SEAT_ID@.
 
@@ -91,7 +91,7 @@ Beállításra kerül és használható egy új munkaállomás: @SEAT_ID@.
 Subject: A munkaállomás eltávolítva: @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 A munkaállomás el lett távolítva, és már nem érhető el: @SEAT_ID@
 
index c1375cca3ef228049c32f83244bf4364315c5768..c7ef447e5a03b97156a9146b7ed6a0e6db5d437f 100644 (file)
@@ -97,7 +97,7 @@ segnalare la troncatura.
 Subject: La nuova sessione @SESSION_ID@ è stata creata per l'utente @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Una nuova sessione con ID @SESSION_ID@ è stata creata per l'utente @USER_ID@.
 
@@ -108,7 +108,7 @@ Il processo primario della sessione è @LEADER@.
 Subject: La sessione @SESSION_ID@ è terminata
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 La sessione con ID @SESSION_ID@ è terminata.
 
@@ -117,7 +117,7 @@ La sessione con ID @SESSION_ID@ è terminata.
 Subject: La nuova postazione @SEAT_ID@ è ora disponibile
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 La nuova postazione @SEAT_ID@ è stata configurata ed è ora disponibile.
 
@@ -126,7 +126,7 @@ La nuova postazione @SEAT_ID@ è stata configurata ed è ora disponibile.
 Subject: La postazione @SEAT_ID@ è stata rimossa
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 La postazione @SEAT_ID@ è stata rimossa e non è più disponibile.
 
index 59fbde8b624f29aff0523b27e3d98feed446ee45..73d414d92d804c6e3406c6884780c22b273c4233 100644 (file)
@@ -86,7 +86,7 @@ Documentation: man:core(5)
 Subject: @USER_ID@ 사용자의 새 @SESSION_ID@ 세션 만듦
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 @USER_ID@ 사용자의 새 @SESSION_ID@ 세션을 만들었습니다.
 
@@ -96,7 +96,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: @SESSION_ID@ 세션 마침
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 @SESSION_ID@ 세션을 끝냈습니다.
 
@@ -104,7 +104,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 새 @SEAT_ID@ 시트 사용할 수 있음
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 새 @SEAT_ID@ 시트를 설정했고 사용할 수 있습니다.
 
@@ -112,7 +112,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: @SEAT_ID@ 시트 제거함
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 @SEAT_ID@ 시트를 제거했으며 더이상 사용할 수 없습니다.
 
index f82bab8fc34eb40b5b536c1bf0e3edccebbd0d22..9881a6c6d1560cb57e5d3b963b17be968d681c60 100644 (file)
@@ -92,7 +92,7 @@ gdb(1) będą ostrzegały o skróceniu pliku.
 Subject: Utworzono nową sesję @SESSION_ID@ dla użytkownika @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Nowa sesja o identyfikatorze @SESSION_ID@ została utworzona dla użytkownika
 @USER_ID@.
@@ -103,7 +103,7 @@ Proces prowadzący sesji: @LEADER@.
 Subject: Zakończono sesję @SESSION_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Sesja o identyfikatorze @SESSION_ID@ została zakończona.
 
@@ -111,7 +111,7 @@ Sesja o identyfikatorze @SESSION_ID@ została zakończona.
 Subject: Dostępne jest nowe stanowisko @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Nowe stanowisko @SEAT_ID@ zostało skonfigurowane i jest teraz dostępne.
 
@@ -119,7 +119,7 @@ Nowe stanowisko @SEAT_ID@ zostało skonfigurowane i jest teraz dostępne.
 Subject: Usunięto stanowisko @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Stanowisko @SEAT_ID@ zostało usunięte i nie jest już dostępne.
 
index edaefb71648142998e2d4f73c5679a7a32d970c5..c07171674dacc66bd2f80c1a5cc004263e4a9813 100644 (file)
@@ -65,7 +65,7 @@ deveria ser relatado para seu fabricante como um erro.
 Subject: A nova sessão @SESSION_ID@ foi criada para usuário o @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Uma nova sessão com o ID @SESSION_ID@ foi criada para o usuário @USER_ID@.
 
@@ -75,7 +75,7 @@ O processo originador da sessão é @LEADER@.
 Subject: Sessão @SESSION_ID@ foi terminada
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Um sessão com o ID @SESSION_ID@ foi terminada.
 
@@ -83,7 +83,7 @@ Um sessão com o ID @SESSION_ID@ foi terminada.
 Subject: Um novo seat @SEAT_ID@ está disponível
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Um novo seat @SEAT_ID@ foi configurado e está disponível.
 
@@ -91,7 +91,7 @@ Um novo seat @SEAT_ID@ foi configurado e está disponível.
 Subject: Seat @SEAT_ID@ foi removido agora
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Um seat @SEAT_ID@ foi removido e não está mais disponível.
 
index ccdc685037962e89a3414154d2e413bb58f20997..9f100551dc9e6aa0fe7f9e333b1630be2660aeea 100644 (file)
@@ -105,7 +105,7 @@ Documentation: man:coredump.conf(5)
 Subject: Для пользователя @USER_ID@ создан новый сеанс @SESSION_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Для пользователя @USER_ID@ создан новый сеанс с идентификатором @SESSION_ID@.
 
@@ -116,7 +116,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Сеанс @SESSION_ID@ завершен
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Сеанс с идентификатором @SESSION_ID@ завершился.
 
@@ -125,7 +125,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Добавлено новое рабочее место @SEAT_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Новое рабочее место (seat) @SEAT_ID@ полностью настроено и готово к
 использованию.
@@ -135,7 +135,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Рабочее место @SEAT_ID@ отключено
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Рабочее место (seat) @SEAT_ID@ было отключено.
 
index 7cb6546d432316a06abb7169f02231217b2d9207..26c44b2a2b9e7d1a03c2b46075ab4cf19628d7ef 100644 (file)
@@ -63,7 +63,7 @@ Documentation: man:core(5)
 Subject: Нова сесија @SESSION_ID@ је направљена за корисника @USER_ID@
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Нова сесија са ИБ-ом @SESSION_ID@ је направљена за корисника @USER_ID@.
 
@@ -73,7 +73,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Сесија @SESSION_ID@ је окончана
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Сесија са ИБ-ом @SESSION_ID@ је окончана.
 
@@ -81,7 +81,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Ново седиште @SEAT_ID@ је сада доступно
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Ново седиште @SEAT_ID@ је исподешавано и сада је доступно.
 
@@ -89,7 +89,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: Седиште @SEAT_ID@ је сада уклоњено
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Седиште @SEAT_ID@ је сада уклоњено и више није доступно.
 
index d6ac2592b8d7116a738d3e70f8b6e13d705db277..5bae69911a07135a57ff64f3383e8213d511392a 100644 (file)
@@ -62,7 +62,7 @@ Documentation: man:core(5)
 Subject: 一个新会话 @SESSION_ID@ 已为用户 @USER_ID@ 建立
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一个 ID 为 @SESSION_ID@ 的新会话已为用户 @USER_ID@ 建立。
 
@@ -72,7 +72,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 会话 @SESSION_ID@ 已终止
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一个 ID 为 @SESSION_ID@ 的会话已终止。
 
@@ -80,7 +80,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 一个新的座位 @SEAT_ID@ 可用
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一个新的座位 @SEAT_ID@ 已被配置并已可用。
 
@@ -88,7 +88,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 座位 @SEAT_ID@ 已被移除
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 座位 @SEAT_ID@ 已被移除并不再可用。
 
index a468c2f6bf34852ab09862731ef8ac27b1830c04..a6ddf2c1333a7a9de762f7156f2e8c849f5a9a31 100644 (file)
@@ -65,7 +65,7 @@ Documentation: man:core(5)
 Subject: 新的工作階段 @SESSION_ID@ 已為使用者 @USER_ID@ 建立
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一個新的工作階段,ID @SESSION_ID@ 已為使用者 @USER_ID@ 建立。
 
@@ -75,7 +75,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 工作階段 @SESSION_ID@ 已結束
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一個工作階段,ID @SESSION_ID@ 已結束。
 
@@ -83,7 +83,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 新的座位 @SEAT_ID@ 可用
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 一個新的座位 @SEAT_ID@ 已被設定且現在可用。
 
@@ -91,7 +91,7 @@ Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
 Subject: 座位 @SEAT_ID@ 已被移除
 Defined-By: systemd
 Support: %SUPPORT_URL%
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 座位 @SEAT_ID@ 已被移除且不再可用。
 
index 45627c98019bbee737a980761385f3674af25de9..3720497bef9f60b526c16f76be2f403a3b029c8d 100644 (file)
@@ -9,3 +9,8 @@ expression s;
 @@
 - (empty_or_root(s) ? "/" : s)
 + empty_to_root(s)
+@@
+expression s;
+@@
+- (s ? s : "/")
++ empty_to_root(s)
index 957d828a8376abc6ad0af8cfd9842995e819cb42..3fce0f4caaee1a98029276a786b1e6288c6b23f7 100644 (file)
@@ -2,13 +2,28 @@
 expression e;
 statement s;
 @@
-- if (e == NULL)
-+ if (!e)
-s
+if (
+(
+!e
+|
+- e == NULL
++ !e
+)
+   )
+   {...}
+else s
+
 @@
 expression e;
 statement s;
 @@
-- if (e != NULL)
-+ if (e)
-s
+if (
+(
+e
+|
+- e != NULL
++ e
+)
+   )
+   {...}
+else s
diff --git a/coccinelle/errno-check.cocci b/coccinelle/errno-check.cocci
new file mode 100644 (file)
index 0000000..709cb4a
--- /dev/null
@@ -0,0 +1,10 @@
+@@
+constant c;
+@@
+(
+- errno == -c
++ errno == c
+|
+- errno != -c
++ errno != c
+)
index 73966b02e5d27861900299f0a5adecd4f1fa0db2..f6cc8ba68a08aac2ddbb286e58171bf452bd45d5 100644 (file)
@@ -1,7 +1,13 @@
 @@
-/* Disable this transformation for the securebits-util.h, as it makes
- * the expression there confusing. */
-position p : script:python() { p[0].file != "src/shared/securebits-util.h" };
+/* Disable this transformation in cases where it doesn't make sense or
+ * where it makes the resulting expression more confusing
+ */
+position p : script:python() {
+            not (p[0].file == "src/shared/securebits-util.h" or
+                 p[0].file == "src/core/manager.h" or
+                 p[0].current_element == "log_set_max_level_realm" or
+                 p[0].current_element == "unichar_is_valid")
+        };
 expression x, y;
 @@
 (
index 2c9b94ceb67438418efdbc5e42604a598dc1caa6..1c17c7df1f4d9c1a990a011b37a2685f05638e76 100644 (file)
@@ -1,25 +1,13 @@
+/* Limit the number of expressions to 6 for performance reasons */
 @@
 expression e;
 /* Exclude JsonVariant * from the transformation, as it can't work with the
  * current version of the IN_SET macro */
 typedef JsonVariant;
 type T != JsonVariant*;
-constant T n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;
+constant T n0, n1, n2, n3, n4, n5;
 @@
-
 (
-- e == n0 || e == n1 || e == n2 || e == n3 || e == n4 || e == n5 || e == n6 || e == n7 || e == n8 || e == n9
-+ IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9)
-|
-- e == n0 || e == n1 || e == n2 || e == n3 || e == n4 || e == n5 || e == n6 || e == n7 || e == n8
-+ IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7, n8)
-|
-- e == n0 || e == n1 || e == n2 || e == n3 || e == n4 || e == n5 || e == n6 || e == n7
-+ IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7)
-|
-- e == n0 || e == n1 || e == n2 || e == n3 || e == n4 || e == n5 || e == n6
-+ IN_SET(e, n0, n1, n2, n3, n4, n5, n6)
-|
 - e == n0 || e == n1 || e == n2 || e == n3 || e == n4 || e == n5
 + IN_SET(e, n0, n1, n2, n3, n4, n5)
 |
diff --git a/coccinelle/macros.h b/coccinelle/macros.h
new file mode 100644 (file)
index 0000000..62177f0
--- /dev/null
@@ -0,0 +1,231 @@
+/* Collected macros from our systemd codebase to make the cocci semantic
+ * parser happy. Inspired by the original cocci macros file
+ * /usr/lib64/coccinelle/standard.h (including the YACFE_* symbols)
+ */
+
+// General
+#define PTR_TO_PID(x)
+
+// src/basic/macro.h
+#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
+#define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
+#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 _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)))
+#define _fallthrough_
+#define _noreturn_ __attribute__((__noreturn__))
+#define thread_local __thread
+
+#define ELEMENTSOF(x)                                                   \
+        (__builtin_choose_expr(                                         \
+                !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
+                sizeof(x)/sizeof((x)[0]),                               \
+                VOID_0))
+
+// src/basic/umask-util.h
+#define _cleanup_umask_
+#define RUN_WITH_UMASK(mask)                                            \
+        for (_cleanup_umask_ mode_t _saved_umask_ = umask(mask) | S_IFMT; \
+             FLAGS_SET(_saved_umask_, S_IFMT);                          \
+             _saved_umask_ &= 0777)
+
+// src/basic/hashmap.h
+#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
+#define HASHMAP_FOREACH(e, h) YACFE_ITERATOR
+#define ORDERED_HASHMAP_FOREACH(e, h) YACFE_ITERATOR
+#define HASHMAP_FOREACH_KEY(e, k, h) YACFE_ITERATOR
+#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h) YACFE_ITERATOR
+
+// src/basic/list.h
+#define LIST_HEAD(t,name)                                               \
+        t *name
+#define LIST_FIELDS(t,name)                                             \
+        t *name##_next, *name##_prev
+#define LIST_HEAD_INIT(head)                                            \
+        do {                                                            \
+                (head) = NULL;                                          \
+        } while (false)
+#define LIST_INIT(name,item)                                            \
+        do {                                                            \
+                typeof(*(item)) *_item = (item);                        \
+                assert(_item);                                          \
+                _item->name##_prev = _item->name##_next = NULL;         \
+        } while (false)
+#define LIST_PREPEND(name,head,item)                                    \
+        do {                                                            \
+                typeof(*(head)) **_head = &(head), *_item = (item);     \
+                assert(_item);                                          \
+                if ((_item->name##_next = *_head))                      \
+                        _item->name##_next->name##_prev = _item;        \
+                _item->name##_prev = NULL;                              \
+                *_head = _item;                                         \
+        } while (false)
+#define LIST_APPEND(name,head,item)                                     \
+        do {                                                            \
+                typeof(*(head)) **_hhead = &(head), *_tail;             \
+                LIST_FIND_TAIL(name, *_hhead, _tail);                   \
+                LIST_INSERT_AFTER(name, *_hhead, _tail, item);          \
+        } while (false)
+#define LIST_REMOVE(name,head,item)                                     \
+        do {                                                            \
+                typeof(*(head)) **_head = &(head), *_item = (item);     \
+                assert(_item);                                          \
+                if (_item->name##_next)                                 \
+                        _item->name##_next->name##_prev = _item->name##_prev; \
+                if (_item->name##_prev)                                 \
+                        _item->name##_prev->name##_next = _item->name##_next; \
+                else {                                                  \
+                        assert(*_head == _item);                        \
+                        *_head = _item->name##_next;                    \
+                }                                                       \
+                _item->name##_next = _item->name##_prev = NULL;         \
+        } while (false)
+#define LIST_FIND_HEAD(name,item,head)                                  \
+        do {                                                            \
+                typeof(*(item)) *_item = (item);                        \
+                if (!_item)                                             \
+                        (head) = NULL;                                  \
+                else {                                                  \
+                        while (_item->name##_prev)                      \
+                                _item = _item->name##_prev;             \
+                        (head) = _item;                                 \
+                }                                                       \
+        } while (false)
+#define LIST_FIND_TAIL(name,item,tail)                                  \
+        do {                                                            \
+                typeof(*(item)) *_item = (item);                        \
+                if (!_item)                                             \
+                        (tail) = NULL;                                  \
+                else {                                                  \
+                        while (_item->name##_next)                      \
+                                _item = _item->name##_next;             \
+                        (tail) = _item;                                 \
+                }                                                       \
+        } while (false)
+#define LIST_INSERT_AFTER(name,head,a,b)                                \
+        do {                                                            \
+                typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
+                assert(_b);                                             \
+                if (!_a) {                                              \
+                        if ((_b->name##_next = *_head))                 \
+                                _b->name##_next->name##_prev = _b;      \
+                        _b->name##_prev = NULL;                         \
+                        *_head = _b;                                    \
+                } else {                                                \
+                        if ((_b->name##_next = _a->name##_next))        \
+                                _b->name##_next->name##_prev = _b;      \
+                        _b->name##_prev = _a;                           \
+                        _a->name##_next = _b;                           \
+                }                                                       \
+        } while (false)
+#define LIST_INSERT_BEFORE(name,head,a,b)                               \
+        do {                                                            \
+                typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
+                assert(_b);                                             \
+                if (!_a) {                                              \
+                        if (!*_head) {                                  \
+                                _b->name##_next = NULL;                 \
+                                _b->name##_prev = NULL;                 \
+                                *_head = _b;                            \
+                        } else {                                        \
+                                typeof(*(head)) *_tail = (head);        \
+                                while (_tail->name##_next)              \
+                                        _tail = _tail->name##_next;     \
+                                _b->name##_next = NULL;                 \
+                                _b->name##_prev = _tail;                \
+                                _tail->name##_next = _b;                \
+                        }                                               \
+                } else {                                                \
+                        if ((_b->name##_prev = _a->name##_prev))        \
+                                _b->name##_prev->name##_next = _b;      \
+                        else                                            \
+                                *_head = _b;                            \
+                        _b->name##_next = _a;                           \
+                        _a->name##_prev = _b;                           \
+                }                                                       \
+        } while (false)
+
+#define LIST_JUST_US(name,item)                                         \
+        (!(item)->name##_prev && !(item)->name##_next)                  \
+#define LIST_FOREACH(name,i,head)                                       \
+        for ((i) = (head); (i); (i) = (i)->name##_next)
+#define LIST_FOREACH_SAFE(name,i,n,head)                                \
+        for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
+#define LIST_FOREACH_BEFORE(name,i,p)                                   \
+        for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
+#define LIST_FOREACH_AFTER(name,i,p)                                    \
+        for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
+#define LIST_FOREACH_OTHERS(name,i,p)                                   \
+        for (({                                                         \
+                (i) = (p);                                              \
+                while ((i) && (i)->name##_prev)                         \
+                        (i) = (i)->name##_prev;                         \
+                if ((i) == (p))                                         \
+                        (i) = (p)->name##_next;                         \
+             });                                                        \
+             (i);                                                       \
+             (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next)
+#define LIST_LOOP_BUT_ONE(name,i,head,p)                                \
+        for ((i) = (p)->name##_next ? (p)->name##_next : (head);        \
+             (i) != (p);                                                \
+             (i) = (i)->name##_next ? (i)->name##_next : (head))
+
+#define LIST_IS_EMPTY(head)                                             \
+        (!(head))
+#define LIST_JOIN(name,a,b)                                             \
+        do {                                                            \
+                assert(b);                                              \
+                if (!(a))                                               \
+                        (a) = (b);                                      \
+                else {                                                  \
+                        typeof(*(a)) *_head = (b), *_tail;              \
+                        LIST_FIND_TAIL(name, (a), _tail);               \
+                        _tail->name##_next = _head;                     \
+                        _head->name##_prev = _tail;                     \
+                }                                                       \
+                (b) = NULL;                                             \
+        } while (false)
+
+// src/basic/strv.h
+#define STRV_FOREACH(s, l) YACFE_ITERATOR
+#define STRV_FOREACH_BACKWARDS(s, l) YACFE_ITERATOR
+#define STRV_FOREACH_PAIR(x, y, l) YACFE_ITERATOR
+
+// src/basic/socket-util.h
+#define CMSG_BUFFER_TYPE(size)                                          \
+        union {                                                         \
+                struct cmsghdr cmsghdr;                                 \
+                uint8_t buf[size];                                      \
+                uint8_t align_check[(size) >= CMSG_SPACE(0) &&          \
+                                    (size) == CMSG_ALIGN(size) ? 1 : -1]; \
+        }
+
+// src/libsystemd/sd-device/device-util.h
+#define FOREACH_DEVICE_PROPERTY(device, key, value) YACFE_ITERATOR
+#define FOREACH_DEVICE_TAG(device, tag) YACFE_ITERATOR
+#define FOREACH_DEVICE_CURRENT_TAG(device, tag) YACFE_ITERATOR
+#define FOREACH_DEVICE_SYSATTR(device, attr) YACFE_ITERATOR
+#define FOREACH_DEVICE_DEVLINK(device, devlink) YACFE_ITERATOR
+#define FOREACH_DEVICE(enumerator, device) YACFE_ITERATOR
+#define FOREACH_SUBSYSTEM(enumerator, device) YACFE_ITERATOR
+
+// src/basic/dirent-util.h
+#define FOREACH_DIRENT(de, d, on_error) YACFE_ITERATOR
+#define FOREACH_DIRENT_ALL(de, d, on_error) YACFE_ITERATOR
index aed2c3490c4f75485c2d5672058b285073322a3a..3486cff5df10901c3aaae2a2a6b1008e3e85e35a 100644 (file)
@@ -1,22 +1,11 @@
+/* Limit the number of expressions to 6 for performance reasons */
 @@
 expression e;
 typedef JsonVariant;
 type T != JsonVariant*;
-constant T n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;
+constant T n0, n1, n2, n3, n4, n5;
 @@
 (
-- e != n0 && e != n1 && e != n2 && e != n3 && e != n4 && e != n5 && e != n6 && e != n7 && e != n8 && e != n9
-+ !IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9)
-|
-- e != n0 && e != n1 && e != n2 && e != n3 && e != n4 && e != n5 && e != n6 && e != n7 && e != n8
-+ !IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7, n8)
-|
-- e != n0 && e != n1 && e != n2 && e != n3 && e != n4 && e != n5 && e != n6 && e != n7
-+ !IN_SET(e, n0, n1, n2, n3, n4, n5, n6, n7)
-|
-- e != n0 && e != n1 && e != n2 && e != n3 && e != n4 && e != n5 && e != n6
-+ !IN_SET(e, n0, n1, n2, n3, n4, n5, n6)
-|
 - e != n0 && e != n1 && e != n2 && e != n3 && e != n4 && e != n5
 + !IN_SET(e, n0, n1, n2, n3, n4, n5)
 |
index be80a76a5f3b50cb0c60dd96e8d5bd3176541d4c..871547a881d20c6a0b3dba06d64329976573b7d1 100755 (executable)
@@ -10,7 +10,6 @@ EXCLUDED_PATHS=(
 )
 
 top="$(git rev-parse --show-toplevel)"
-iso_defs="$top/coccinelle/systemd-definitions.iso"
 args=
 
 # Create an array from files tracked by git...
@@ -32,12 +31,12 @@ if ! parallel -h >/dev/null; then
     exit 1
 fi
 
-for SCRIPT in ${@-$top/coccinelle/*.cocci} ; do
+for SCRIPT in ${@-$top/coccinelle/*.cocci}; do
     echo "--x-- Processing $SCRIPT --x--"
     TMPFILE=`mktemp`
     echo "+ spatch --sp-file $SCRIPT $args ..."
     parallel --halt now,fail=1 --keep-order --noswap --max-args=20 \
-             spatch --iso-file $iso_defs --sp-file $SCRIPT $args ::: "${files[@]}" \
+             spatch --macro-file="$top/coccinelle/macros.h" --sp-file $SCRIPT $args ::: "${files[@]}" \
              2>"$TMPFILE" || cat "$TMPFILE"
     echo -e "--x-- Processed $SCRIPT --x--\n"
 done
index 675760e37a41b6f8224547105d7768690c5056fd..46f70c4c23682a4d6027b43bc05d9e12c01caa82 100644 (file)
@@ -1,16 +1,15 @@
 @@
-expression list args;
-@@
-- strjoin(args, NULL);
-+ strjoin(args);
-@@
+position p : script:python() { p[0].current_element != "test_strjoin" };
 expression t;
 expression list args;
 @@
-- t = strjoin(args, NULL);
+(
+- strjoin@p(args, NULL);
++ strjoin(args);
+|
+- t = strjoin@p(args, NULL);
 + t = strjoin(args);
-@@
-expression list args;
-@@
-- return strjoin(args, NULL);
+|
+- return strjoin@p(args, NULL);
 + return strjoin(args);
+)
diff --git a/coccinelle/systemd-definitions.iso b/coccinelle/systemd-definitions.iso
deleted file mode 100644 (file)
index 92db763..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Statement isomorphisms - replace explicit checks against NULL with a
- * shorter variant, which relies on C's downgrade-to-bool feature.
- * The expression metavariables should be declared as pointers, however,
- * that doesn't work well with complex expressions like:
- * if (UNIT(p)->default_dependencies != NULL)
- */
-
-Statement
-@@
-expression X;
-statement S;
-@@
-if (X == NULL) S => if (!X) S
-
-Statement
-@@
-expression X;
-statement S;
-@@
-if (X != NULL) S => if (X) S
index 401216ad728a431b6cef5227c5ac5123c60b31c7..660a35e3f4d9b340a5e90db9a1138ff44b8cf635 100644 (file)
@@ -1,6 +1,7 @@
 @@
+position p : script:python() { not p[0].file.startswith("man/") };
 expression e, fmt;
 expression list vaargs;
 @@
-- snprintf(e, sizeof(e), fmt, vaargs);
+- snprintf@p(e, sizeof(e), fmt, vaargs);
 + xsprintf(e, fmt, vaargs);
diff --git a/coccinelle/zz-drop-braces.cocci b/coccinelle/zz-drop-braces.cocci
new file mode 100644 (file)
index 0000000..34bf12f
--- /dev/null
@@ -0,0 +1,27 @@
+@@
+position p : script:python() { p[0].file != "src/journal/lookup3.c" };
+identifier id;
+expression e;
+@@
+if (...)
+- {
+(
+    id@p(...);
+|
+    e@p;
+)
+- }
+
+@@
+position p : script:python() { p[0].file != "src/journal/lookup3.c" };
+identifier id;
+expression e;
+@@
+if (...)
+- {
+(
+    return id@p(...);
+|
+    return e@p;
+)
+- }
index f122eda417280cf10fa91354a1fc7dcea7622229..82df155f1e99d987ff9cc70d0d0f1e4b9cebaf86 100644 (file)
@@ -28,23 +28,34 @@ 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.
+`inotify()` `IN_CLOSE_WRITE` 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
-`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
+finish. Second, after the lock is taken, it can be sure 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.
+the device node again. Secondly, it results an `IN_CLOSE_WRITE` event, which
+causes `systemd-udevd` to immediately re-process the device — seeing all
+changes the tool made — and notify subscribed clients about it.
+
+Ideally, `systemd-udevd` would explicitly watch block devices for `LOCK_EX`
+locks being released. Such monitoring is not supported on Linux however, which
+is why it watches for `IN_CLOSE_WRITE` instead, i.e. for `close()` calls to
+writable file descriptors referring to the block device. In almost all cases,
+the difference between these two events does not matter much, as any locks
+taken are implicitly released by `close()`. However, it should be noted that if
+an application unlocks a device after completing its work without closing it,
+i.e. while keeping the file descriptor open for further, longer time, then
+`systemd-udevd` will not notice this and not retrigger and thus reprobe the
+device.
 
 Besides synchronizing block device access between `systemd-udevd` and such
 tools this scheme may also be used to synchronize access between those tools
index 803ba5440faffc6a3a76120fa9222dcd5e161505..715b14e0e493ba524c1cd04b0567ae05f2a79a31 100644 (file)
@@ -114,7 +114,23 @@ We define two directories below `$BOOT`:
 
 **Note:** _In all cases the `/loader/` directory should be located directly in the root of the file system. Specifically, if `$BOOT` is the ESP, then `/loader/` directory should be located directly in the root directory of the ESP, and not in the `/EFI/` subdirectory._
 
-Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or more configuration snippets with the suffix ".conf", one for each boot menu item. The file name of the file is used for identification of the boot item but shall never be presented to the user in the UI. The file name may be chosen freely but should be unique enough to avoid clashes between OS installations. More specifically it is suggested to include the machine ID (`/etc/machine-id` or the D-Bus machine ID for OSes that lack `/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS identifier (The ID field of `/etc/os-release`). Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
+Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or
+more configuration snippets with the suffix ".conf", one for each boot menu
+item. The file name of the file is used for identification of the boot item but
+shall never be presented to the user in the UI. The file name may be chosen
+freely but should be unique enough to avoid clashes between OS
+installations. More specifically it is suggested to include the machine ID
+(`/etc/machine-id` or the D-Bus machine ID for OSes that lack
+`/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS
+identifier (The ID field of `/etc/os-release`). Example:
+`$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
+
+In order to maximize compatibility with file system implementations and
+restricted boot loader environments, and to minimize conflicting character use
+with other progams, file names shall be chosen from a restricted character set:
+ASCII upper and lower case characters, digits, "+", "-", "_" and ".". Also, the
+file names should have a length of at least one and at most 255 characters
+(including file name suffix).
 
 These configuration snippets shall be Unix-style text files (i.e. line separation with a single newline character), in the UTF-8 encoding. The configuration snippets are loosely inspired on Grub1's configuration syntax. Lines beginning with '#' shall be ignored and used for commenting. The first word of a line is used as key and shall be separated by one or more spaces from its value. The following keys are known:
 
@@ -171,6 +187,10 @@ extension `.efi`. Support for images of this type is of course specific to
 systems with EFI firmware. Ignore this section if you work on systems not
 supporting EFI.
 
+Type #2 file names should be chosen from the same restricted character set as
+Type #1 described above (but use a different file name suffix of `.efi` instead
+of `.conf`).
+
 Images of this type have the advantage that all metadata and payload that makes
 up the boot entry is monopolized in a single PE file that can be signed
 cryptographically as one for the purpose of EFI SecureBoot.
index 11cc6222e358046efaf5c3cbae371d6167973c62..8f9b2d43b8474c042a35a45b7d8f76838aef11d5 100644 (file)
@@ -36,6 +36,8 @@ layout: default
           int a, b, c;
   ```
 
+  (i.e. use double indentation — 16 spaces — for the parameter list.)
+
 - Try to write this:
 
   ```c
@@ -84,7 +86,27 @@ layout: default
 
 - Do not write functions that clobber call-by-reference variables on
   failure. Use temporary variables for these cases and change the passed in
-  variables only on success.
+  variables only on success. The rule is: never clobber return parameters on
+  failure, always initialize return parameters on success.
+
+- Typically, function parameters fit into three categories: input parameters,
+  mutable objects, and call-by-reference return parameters. Input parameters
+  should always carry suitable "const" declarators if they are pointers, to
+  indicate they are input-only and not changed by the function. Return
+  parameters are best prefixed with "ret_", to clarify they are return
+  parameters. (Conversely, please do not prefix parameters that aren't
+  output-only with "ret_", in particular not mutable parameters that are both
+  input as well as output). Example:
+
+  ```c
+  static int foobar_frobnicate(
+                  Foobar* object,            /* the associated mutable object */
+                  const char *input,         /* immutable input parameter */
+                  char **ret_frobnicated) {  /* return parameter */
+          …
+          return 0;
+  }
+  ```
 
 - The order in which header files are included doesn't matter too
   much. systemd-internal headers must not rely on an include order, so it is
@@ -307,13 +329,16 @@ layout: default
 ## Logging
 
 - For every function you add, think about whether it is a "logging" function or
-  a "non-logging" function. "Logging" functions do logging on their own,
-  "non-logging" function never log on their own and expect their callers to
-  log. All functions in "library" code, i.e. in `src/shared/` and suchlike must
-  be "non-logging". Every time a "logging" function calls a "non-logging"
-  function, it should log about the resulting errors. If a "logging" function
-  calls another "logging" function, then it should not generate log messages,
-  so that log messages are not generated twice for the same errors.
+  a "non-logging" function. "Logging" functions do (non-debug) logging on their
+  own, "non-logging" function never log on their own (except at debug level)
+  and expect their callers to log. All functions in "library" code, i.e. in
+  `src/shared/` and suchlike must be "non-logging". Every time a "logging"
+  function calls a "non-logging" function, it should log about the resulting
+  errors. If a "logging" function calls another "logging" function, then it
+  should not generate log messages, so that log messages are not generated
+  twice for the same errors. (Note that debug level logging — at syslog level
+  `LOG_DEBUG` — is not considered logging in this context, debug logging is
+  generally always fine and welcome.)
 
 - If possible, do a combined log & return operation:
 
index 4b138b593c1442b4d670b0a54192e6c31ceca60c..0caa5cc04846c47618b595e279a3b25c502772ab 100644 (file)
@@ -82,7 +82,7 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy
 | [hostnamed](https://www.freedesktop.org/wiki/Software/systemd/hostnamed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially |
 | [localed](https://www.freedesktop.org/wiki/Software/systemd/localed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially |
 | [timedated](https://www.freedesktop.org/wiki/Software/systemd/timedated) | D-Bus | yes | yes | GNOME | yes | [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially |
-| [initrd interface](https://www.freedesktop.org/wiki/Software/systemd/InitrdInterface) | Environment, flag files | yes | yes | dracut, ArchLinux | yes | ArchLinux | no |
+| [initrd interface](https://systemd.io/INITRD_INTERFACE/) | Environment, flag files | yes | yes | dracut, ArchLinux | yes | ArchLinux | no |
 | [Container interface](https://systemd.io/CONTAINER_INTERFACE) | Environment, Mounts | yes | yes | libvirt/LXC | yes | - | no |
 | [Boot Loader interface](https://systemd.io/BOOT_LOADER_INTERFACE) | EFI variables | yes | yes | gummiboot | yes | - | no |
 | [Service bus API](https://www.freedesktop.org/wiki/Software/systemd/dbus) | D-Bus | yes | yes | system-config-services | no | - | no |
@@ -94,15 +94,15 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy
 | [$XDG_RUNTIME_DIR](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) | Environment | yes | yes | glib, GNOME | yes | - | no |
 | [$LISTEN_FDS $LISTEN_PID FD Passing](https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html) | Environment | yes | yes | numerous (via sd-daemon.h) | yes | - | no |
 | [$NOTIFY_SOCKET Daemon Notifications](https://www.freedesktop.org/software/systemd/man/sd_notify.html) | Environment | yes | yes | a few, including udev | yes | - | no |
-| [argv&#91;0&#93;&#91;0&#93;='@' Logic](https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons) | `/proc` marking | yes | yes | mdadm | yes | - | no |
+| [argv&#91;0&#93;&#91;0&#93;='@' Logic](https://systemd.io/ROOT_STORAGE_DAEMONS/) | `/proc` marking | yes | yes | mdadm | yes | - | no |
 | [Unit file format](https://www.freedesktop.org/software/systemd/man/systemd.unit.html) | File format | yes | yes | numerous | no | - | no |
 | [Network](https://www.freedesktop.org/software/systemd/man/systemd.network.html) & [Netdev file format](https://www.freedesktop.org/software/systemd/man/systemd.netdev.html) | File format | yes | yes | no | no | - | no |
 | [Link file format](https://www.freedesktop.org/software/systemd/man/systemd.link.html) | File format | yes | yes | no | no | - | no |
 | [Journal File Format](https://systemd.io/JOURNAL_FILE_FORMAT) | File format | yes | yes | - | maybe | - | no |
 | [Journal Export Format](https://www.freedesktop.org/wiki/Software/systemd/export) | File format | yes | yes | - | yes | - | no |
 | [Cooperation in cgroup tree](https://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups) | Treaty | yes | yes | libvirt | yes | libvirt | no |
-| [Password Agents](https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents) | Socket+Files | yes | yes | - | yes | - | no |
-| [udev multi-seat properties](https://www.freedesktop.org/wiki/Software/systemd/multiseat) | udev Property | yes | yes | X11, gdm | no | - | no |
+| [Password Agents](https://systemd.io/PASSWORD_AGENTS/) | Socket+Files | yes | yes | - | yes | - | no |
+| [udev multi-seat properties](https://www.freedesktop.org/software/systemd/man/sd-login.html) | udev Property | yes | yes | X11, gdm | no | - | no |
 | udev session switch ACL properties | udev Property | no | no | - | no | - | no |
 | [CLI of systemctl,...](https://www.freedesktop.org/software/systemd/man/systemctl.html) | CLI | yes | yes | numerous | no | - | no |
 | [tmpfiles.d](https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html) | File format | yes | yes | numerous | yes | ArchLinux | partially |
index 779044b0d4e8358134a20c7ec99624e5c2bc8bf3..e18ac45bd0bace56d12538fe4695563a0ccfa757 100644 (file)
@@ -108,9 +108,9 @@ to find a different solution to your problem._
 The recommended way to distinguish between run-from-initrd and run-from-rootfs
 for a daemon is to check for `/etc/initrd-release` (which exists on all modern
 initrd implementations, see the [initrd
-Interface](http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface)
-for details) which when exists results in `argv[0][0]` being set to `@`, and
-otherwise doesn't. Something like this:
+Interface](https://systemd.io/INITRD_INTERFACE/) for details) which when exists
+results in `argv[0][0]` being set to `@`, and otherwise doesn't. Something like
+this:
 
 ```c
 #include <unistd.h>
index 5bb24fa3eecd33aa40d2253cb05f94f1ad0ab4fc..c0f945c8851cf57f0a66783a191297e21524c6dc 100644 (file)
@@ -1,10 +1,10 @@
 ---
-title: Using /tmp/ And /var/tmp/ Safely
+title: Using /tmp/ and /var/tmp/ Safely
 category: Interfaces
 layout: default
 ---
 
-# Using `/tmp/` And `/var/tmp/` Safely
+# Using `/tmp/` and `/var/tmp/` Safely
 
 `/tmp/` and `/var/tmp/` are two world-writable directories Linux systems
 provide for temporary files. The former is typically on `tmpfs` and thus
index f8ff413d28f4f8aecae9edde484b7ebafef1e124..f0dc2ee20ffb88cc6ee5301ae88f27dc8d26351c 100644 (file)
@@ -270,6 +270,9 @@ All cgroup/resource control settings are available for transient units
 ✓ IPAccounting=
 ✓ IPAddressAllow=
 ✓ IPAddressDeny=
+✓ ManagedOOMSwap=
+✓ ManagedOOMMemoryPressure=
+✓ ManagedOOMMemoryPressureLimitPercent=
 ```
 
 ## Process Killing Settings
index 67e6d083ff74aa1423aa330003addf766244803c..e289a9b68ecd6b9bc845f6b5d663b9e97784a31d 100644 (file)
@@ -171,10 +171,11 @@ pick — given that 64K UIDs are assigned to each container according to this
 allocation logic, the maximum UID used for this range is hence
 1878982656+65535=1879048191.)
 
-Note that systemd does not make any of these values runtime-configurable. All
-these boundaries are chosen during build time. That said, the system UID/GID
-boundary is traditionally configured in /etc/login.defs, though systemd won't
-look there during runtime.
+Systemd has compile-time default for these boundaries. Using those defaults is
+recommended. It will nevertheless query `/etc/login.defs` at runtime, when
+compiled with `-Dcompat-mutable-uid-boundaries=true` and that file is present.
+Support for this is considered only a compatibility feature and should not be
+used except when upgrading systems which were creating with different defaults.
 
 ## Considerations for container managers
 
index eac9c0c1594d4fc6b43c65352783dcde29e809fc..ba8f4c215e3db370321c02a5bccf21569077c72c 100644 (file)
@@ -2139,7 +2139,7 @@ OUI:0002C6*
  ID_OUI_FROM_DATABASE=Data Track Technology PLC
 
 OUI:0002C7*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0002C8*
  ID_OUI_FROM_DATABASE=Technocom Communications Technology (pte) Ltd
@@ -2466,7 +2466,7 @@ OUI:000333*
  ID_OUI_FROM_DATABASE=Digitel Co., Ltd.
 
 OUI:000334*
- ID_OUI_FROM_DATABASE=Newport Electronics
+ ID_OUI_FROM_DATABASE=Omega Engineering Inc.
 
 OUI:000335*
  ID_OUI_FROM_DATABASE=Mirae Technology
@@ -5349,13 +5349,13 @@ OUI:0006F4*
  ID_OUI_FROM_DATABASE=Prime Electronics & Satellitics Inc.
 
 OUI:0006F5*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0006F6*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
 OUI:0006F7*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0006F8*
  ID_OUI_FROM_DATABASE=The Boeing Company
@@ -5394,7 +5394,7 @@ OUI:000703*
  ID_OUI_FROM_DATABASE=CSEE Transport
 
 OUI:000704*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:000705*
  ID_OUI_FROM_DATABASE=Endress & Hauser GmbH & Co
@@ -8604,7 +8604,7 @@ OUI:000B4D*
  ID_OUI_FROM_DATABASE=Emuzed
 
 OUI:000B4E*
- ID_OUI_FROM_DATABASE=VertexRSI, General Dynamics SatCOM Technologies, Inc.
+ ID_OUI_FROM_DATABASE=Communications & Power Industries
 
 OUI:000B4F*
  ID_OUI_FROM_DATABASE=Verifone
@@ -15552,7 +15552,7 @@ OUI:001459*
  ID_OUI_FROM_DATABASE=Moram Co., Ltd.
 
 OUI:00145A*
- ID_OUI_FROM_DATABASE=Neratec Solutions AG
+ ID_OUI_FROM_DATABASE=Westermo Neratec AG
 
 OUI:00145B*
  ID_OUI_FROM_DATABASE=SeekerNet Inc.
@@ -16995,7 +16995,7 @@ OUI:00163A*
  ID_OUI_FROM_DATABASE=YVES TECHNOLOGY CO., LTD.
 
 OUI:00163B*
- ID_OUI_FROM_DATABASE=VertexRSI/General Dynamics
+ ID_OUI_FROM_DATABASE=Communications & Power Industries
 
 OUI:00163C*
  ID_OUI_FROM_DATABASE=Rebox B.V.
@@ -17580,7 +17580,7 @@ OUI:0016FD*
  ID_OUI_FROM_DATABASE=Jaty Electronics
 
 OUI:0016FE*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0016FF*
  ID_OUI_FROM_DATABASE=Wamin Optocomm Mfg Corp
@@ -19701,7 +19701,7 @@ OUI:0019C0*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
 OUI:0019C1*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0019C2*
  ID_OUI_FROM_DATABASE=Equustek Solutions, Inc.
@@ -22011,7 +22011,7 @@ OUI:001BFA*
  ID_OUI_FROM_DATABASE=G.i.N. mbH
 
 OUI:001BFB*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:001BFC*
  ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
@@ -23745,7 +23745,7 @@ OUI:001E3C*
  ID_OUI_FROM_DATABASE=Lyngbox Media AB
 
 OUI:001E3D*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:001E3E*
  ID_OUI_FROM_DATABASE=KMW Inc.
@@ -26103,7 +26103,7 @@ OUI:00214E*
  ID_OUI_FROM_DATABASE=GS Yuasa Power Supply Ltd.
 
 OUI:00214F*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:002150*
  ID_OUI_FROM_DATABASE=EYEVIEW ELECTRONICS
@@ -27420,7 +27420,7 @@ OUI:002305*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
 OUI:002306*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:002307*
  ID_OUI_FROM_DATABASE=FUTURE INNOVATION TECH CO.,LTD
@@ -27804,7 +27804,7 @@ OUI:002385*
  ID_OUI_FROM_DATABASE=ANTIPODE
 
 OUI:002386*
- ID_OUI_FROM_DATABASE=Tour & Andersson AB
+ ID_OUI_FROM_DATABASE=IMI Hydronic Engineering international SA
 
 OUI:002387*
  ID_OUI_FROM_DATABASE=ThinkFlood, Inc.
@@ -28320,7 +28320,7 @@ OUI:002432*
  ID_OUI_FROM_DATABASE=Neostar Technology Co.,LTD
 
 OUI:002433*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:002434*
  ID_OUI_FROM_DATABASE=Lectrosonics, Inc.
@@ -29889,7 +29889,7 @@ OUI:002642*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
 OUI:002643*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:002644*
  ID_OUI_FROM_DATABASE=Thomson Telecom Belgium
@@ -29916,7 +29916,7 @@ OUI:00264D*
  ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation
 
 OUI:00264E*
- ID_OUI_FROM_DATABASE=Rail & Road Protec GmbH
+ ID_OUI_FROM_DATABASE=r2p GmbH
 
 OUI:00264F*
  ID_OUI_FROM_DATABASE=Krüger &Gothe GmbH
@@ -31373,6 +31373,9 @@ OUI:0030FF*
 OUI:003146*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:003192*
+ ID_OUI_FROM_DATABASE=TP-Link Corporation Limited
+
 OUI:003217*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -31382,6 +31385,9 @@ OUI:00323A*
 OUI:00336C*
  ID_OUI_FROM_DATABASE=SynapSense Corporation
 
+OUI:0034A1*
+ ID_OUI_FROM_DATABASE=RF-LAMBDA USA INC.
+
 OUI:0034DA*
  ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
 
@@ -33017,6 +33023,9 @@ OUI:0054AF*
 OUI:0054BD*
  ID_OUI_FROM_DATABASE=Swelaser AB
 
+OUI:0055B1*
+ ID_OUI_FROM_DATABASE=Shanghai Baud Data Communication Co.,Ltd.
+
 OUI:0055DA0*
  ID_OUI_FROM_DATABASE=Shinko Technos co.,ltd.
 
@@ -33426,7 +33435,7 @@ OUI:006064*
  ID_OUI_FROM_DATABASE=NETCOMM LIMITED
 
 OUI:006065*
- ID_OUI_FROM_DATABASE=BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH
+ ID_OUI_FROM_DATABASE=B&R Industrial Automation GmbH
 
 OUI:006066*
  ID_OUI_FROM_DATABASE=LACROIX Trafic
@@ -33995,6 +34004,9 @@ OUI:006D61*
 OUI:006DFB*
  ID_OUI_FROM_DATABASE=Vutrix Technologies Ltd
 
+OUI:006E02*
+ ID_OUI_FROM_DATABASE=Xovis AG
+
 OUI:006F64*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -34883,6 +34895,9 @@ OUI:008865*
 OUI:0088BA*
  ID_OUI_FROM_DATABASE=NC&C
 
+OUI:008A55*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:008A96*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -35544,7 +35559,7 @@ OUI:0090D1*
  ID_OUI_FROM_DATABASE=LEICHU ENTERPRISE CO., LTD.
 
 OUI:0090D2*
- ID_OUI_FROM_DATABASE=ARTEL VIDEO SYSTEMS
+ ID_OUI_FROM_DATABASE=Artel Video Systems
 
 OUI:0090D3*
  ID_OUI_FROM_DATABASE=GIESECKE & DEVRIENT GmbH
@@ -36737,6 +36752,9 @@ OUI:00B7A8*
 OUI:00B810*
  ID_OUI_FROM_DATABASE=Yichip Microelectronics (Hangzhou) Co.,Ltd
 
+OUI:00B881*
+ ID_OUI_FROM_DATABASE=New platforms LLC
+
 OUI:00B8B3*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -37586,9 +37604,15 @@ OUI:00C1B1*
 OUI:00C2C6*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:00C343*
+ ID_OUI_FROM_DATABASE=E-T-A Circuit Breakers Ltd
+
 OUI:00C3F4*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:00C52C*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
 OUI:00C5DB*
  ID_OUI_FROM_DATABASE=Datatech Sistemas Digitales Avanzados SL
 
@@ -39302,6 +39326,9 @@ OUI:00E6E8*
 OUI:00E8AB*
  ID_OUI_FROM_DATABASE=Meggitt Training Systems, Inc.
 
+OUI:00E93A*
+ ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
+
 OUI:00EABD*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -39452,6 +39479,9 @@ OUI:0403D6*
 OUI:0404EA*
  ID_OUI_FROM_DATABASE=Valens Semiconductor Ltd.
 
+OUI:0405DD*
+ ID_OUI_FROM_DATABASE=Shenzhen Cultraview Digital Technology Co., Ltd
+
 OUI:04072E*
  ID_OUI_FROM_DATABASE=VTech Electronics Ltd.
 
@@ -39804,7 +39834,7 @@ OUI:0475F5*
  ID_OUI_FROM_DATABASE=CSST
 
 OUI:04766E*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0476B0*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
@@ -39900,7 +39930,7 @@ OUI:049790*
  ID_OUI_FROM_DATABASE=Lartech telecom LLC
 
 OUI:0498F3*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:0499E6*
  ID_OUI_FROM_DATABASE=Shenzhen Yoostar Technology Co., Ltd
@@ -40241,6 +40271,9 @@ OUI:04E662*
 OUI:04E676*
  ID_OUI_FROM_DATABASE=AMPAK Technology, Inc.
 
+OUI:04E77E*
+ ID_OUI_FROM_DATABASE=We Corporation Inc.
+
 OUI:04E795*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -40280,6 +40313,9 @@ OUI:04F169*
 OUI:04F17D*
  ID_OUI_FROM_DATABASE=Tarana Wireless
 
+OUI:04F352*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:04F4BC*
  ID_OUI_FROM_DATABASE=Xena Networks
 
@@ -40910,6 +40946,9 @@ OUI:083869*
 OUI:0838A5*
  ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH
 
+OUI:0838E6*
+ ID_OUI_FROM_DATABASE=Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.
+
 OUI:083A2F*
  ID_OUI_FROM_DATABASE=Guangzhou Juan Intelligent Tech Joint Stock Co.,Ltd
 
@@ -40994,9 +41033,15 @@ OUI:085240*
 OUI:0854BB*
  ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD
 
+OUI:085531*
+ ID_OUI_FROM_DATABASE=Routerboard.com
+
 OUI:085700*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:0858A5*
+ ID_OUI_FROM_DATABASE=Beijing Vrv Software Corpoaration Limited.
+
 OUI:085AE0*
  ID_OUI_FROM_DATABASE=Recovision Technology Co., Ltd.
 
@@ -41027,6 +41072,9 @@ OUI:086266*
 OUI:086361*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:0865F0*
+ ID_OUI_FROM_DATABASE=JM Zengge Co., Ltd
+
 OUI:08661F*
  ID_OUI_FROM_DATABASE=Palo Alto Networks
 
@@ -41096,6 +41144,9 @@ OUI:087A4C*
 OUI:087BAA*
  ID_OUI_FROM_DATABASE=SVYAZKOMPLEKTSERVICE, LLC
 
+OUI:087C39*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:087CBE*
  ID_OUI_FROM_DATABASE=Quintic Corp.
 
@@ -41147,6 +41198,9 @@ OUI:088F2C*
 OUI:0890BA*
  ID_OUI_FROM_DATABASE=Danlaw Inc
 
+OUI:089356*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:0894EF*
  ID_OUI_FROM_DATABASE=Wistron Infocomm (Zhongshan) Corporation
 
@@ -41282,6 +41336,9 @@ OUI:08C6B3*
 OUI:08CA45*
  ID_OUI_FROM_DATABASE=Toyou Feiji Electronics Co., Ltd.
 
+OUI:08CBE5*
+ ID_OUI_FROM_DATABASE=R3 - Reliable Realtime Radio Communications GmbH
+
 OUI:08CC27*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
@@ -41519,6 +41576,9 @@ OUI:0C1539*
 OUI:0C15C5*
  ID_OUI_FROM_DATABASE=SDTEC Co., Ltd.
 
+OUI:0C1773*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:0C17F1*
  ID_OUI_FROM_DATABASE=TELECSYS
 
@@ -41591,6 +41651,9 @@ OUI:0C3021*
 OUI:0C31DC*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:0C354F*
+ ID_OUI_FROM_DATABASE=Nokia
+
 OUI:0C35FE*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
@@ -41609,6 +41672,9 @@ OUI:0C383E*
 OUI:0C3956*
  ID_OUI_FROM_DATABASE=Observator instruments
 
+OUI:0C3AFA*
+ ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
+
 OUI:0C3B50*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -42011,6 +42077,9 @@ OUI:0CB6D2*
 OUI:0CB771*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:0CB789*
+ ID_OUI_FROM_DATABASE=Honor Device Co., Ltd.
+
 OUI:0CB912*
  ID_OUI_FROM_DATABASE=JM-DATA GmbH
 
@@ -42179,6 +42248,9 @@ OUI:0CEC80*
 OUI:0CEC84*
  ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp.
 
+OUI:0CEC8D*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
 OUI:0CEE99*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
@@ -42518,6 +42590,9 @@ OUI:102C6B*
 OUI:102C83*
  ID_OUI_FROM_DATABASE=XIMEA
 
+OUI:102D31*
+ ID_OUI_FROM_DATABASE=Shenzhen Americas Trading Company LLC
+
 OUI:102D96*
  ID_OUI_FROM_DATABASE=Looxcie Inc.
 
@@ -42575,6 +42650,9 @@ OUI:103D3E*
 OUI:103DEA*
  ID_OUI_FROM_DATABASE=HFC Technology (Beijing) Ltd. Co.
 
+OUI:103F44*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:1040F3*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -42722,6 +42800,9 @@ OUI:106FEF*
 OUI:1070FD*
  ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc.
 
+OUI:107100*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:1071F9*
  ID_OUI_FROM_DATABASE=Cloud Telecomputers, LLC
 
@@ -42821,6 +42902,9 @@ OUI:1094BB*
 OUI:10954B*
  ID_OUI_FROM_DATABASE=Megabyte Ltd.
 
+OUI:109693*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:109836*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
@@ -42836,6 +42920,9 @@ OUI:109ADD*
 OUI:109C70*
  ID_OUI_FROM_DATABASE=Prusa Research s.r.o.
 
+OUI:109D7A*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:109E3A*
  ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd.
 
@@ -43010,6 +43097,9 @@ OUI:10D38A*
 OUI:10D542*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:10D7B0*
+ ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
+
 OUI:10DA43*
  ID_OUI_FROM_DATABASE=NETGEAR
 
@@ -43214,6 +43304,9 @@ OUI:14115D*
 OUI:141330*
  ID_OUI_FROM_DATABASE=Anakreon UK LLP
 
+OUI:141333*
+ ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
+
 OUI:141346*
  ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd
 
@@ -43250,6 +43343,9 @@ OUI:141A51*
 OUI:141AA3*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
+OUI:141B30*
+ ID_OUI_FROM_DATABASE=Shenzhen Yipingfang Network Technology Co., Ltd.
+
 OUI:141BBD*
  ID_OUI_FROM_DATABASE=Volex Inc.
 
@@ -43514,6 +43610,9 @@ OUI:145290*
 OUI:145412*
  ID_OUI_FROM_DATABASE=Entis Co., Ltd.
 
+OUI:14563A*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:145645*
  ID_OUI_FROM_DATABASE=Savitech Corp.
 
@@ -43574,6 +43673,9 @@ OUI:146A0B*
 OUI:146B72*
  ID_OUI_FROM_DATABASE=Shenzhen Fortune Ship Technology Co., Ltd.
 
+OUI:146B9A*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:146B9C*
  ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD
 
@@ -43622,6 +43724,9 @@ OUI:148692*
 OUI:14876A*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:1488E6*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:14893E*
  ID_OUI_FROM_DATABASE=VIXTEL TECHNOLOGIES LIMTED
 
@@ -43727,6 +43832,9 @@ OUI:14A9D0*
 OUI:14A9E3*
  ID_OUI_FROM_DATABASE=MST CORPORATION
 
+OUI:14AB02*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:14AB56*
  ID_OUI_FROM_DATABASE=WUXI FUNIDE DIGITAL CO.,LTD
 
@@ -44021,6 +44129,9 @@ OUI:180F76*
 OUI:18104E*
  ID_OUI_FROM_DATABASE=CEDINT-UPM
 
+OUI:181171*
+ ID_OUI_FROM_DATABASE=Guangzhou Doctorpai Education & Technology Co.,Ltd
+
 OUI:181212*
  ID_OUI_FROM_DATABASE=Cepton Technologies
 
@@ -44135,6 +44246,9 @@ OUI:183451*
 OUI:1835D1*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:183672*
+ ID_OUI_FROM_DATABASE=Shaoxing ShunChuang Technology CO.,LTD
+
 OUI:1836FC*
  ID_OUI_FROM_DATABASE=Elecsys International Corporation
 
@@ -44198,6 +44312,9 @@ OUI:184462*
 OUI:1844E6*
  ID_OUI_FROM_DATABASE=zte corporation
 
+OUI:184516*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:184593*
  ID_OUI_FROM_DATABASE=Taicang T&W Electronics
 
@@ -44240,6 +44357,9 @@ OUI:184ECB*
 OUI:184F32*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:184F5D*
+ ID_OUI_FROM_DATABASE=JRC Mobility Inc.
+
 OUI:18502A*
  ID_OUI_FROM_DATABASE=SOARNEX
 
@@ -44285,6 +44405,9 @@ OUI:185A58*
 OUI:185AE8*
  ID_OUI_FROM_DATABASE=Zenotech.Co.,Ltd
 
+OUI:185BB3*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:185D9A*
  ID_OUI_FROM_DATABASE=BobjGear LLC
 
@@ -44420,6 +44543,9 @@ OUI:18863A*
 OUI:1886AC*
  ID_OUI_FROM_DATABASE=Nokia Danmark A/S
 
+OUI:188740*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:188796*
  ID_OUI_FROM_DATABASE=HTC Corporation
 
@@ -44615,6 +44741,9 @@ OUI:18B430*
 OUI:18B591*
  ID_OUI_FROM_DATABASE=I-Storm
 
+OUI:18B6CC*
+ ID_OUI_FROM_DATABASE=We Corporation Inc.
+
 OUI:18B6F7*
  ID_OUI_FROM_DATABASE=NEW POS TECHNOLOGY LIMITED
 
@@ -44666,6 +44795,9 @@ OUI:18C58A*
 OUI:18C8E7*
  ID_OUI_FROM_DATABASE=Shenzhen Hualistone Technology Co.,Ltd
 
+OUI:18CC18*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:18CC23*
  ID_OUI_FROM_DATABASE=Philio Technology Corporation
 
@@ -44771,6 +44903,9 @@ OUI:18ECE7*
 OUI:18EE69*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:18EE86*
+ ID_OUI_FROM_DATABASE=Novatel Wireless Solutions, Inc.
+
 OUI:18EF63*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -45050,6 +45185,9 @@ OUI:1C2AA3*
 OUI:1C2E1B*
  ID_OUI_FROM_DATABASE=Suzhou Tremenet Communication Technology Co., Ltd.
 
+OUI:1C3008*
+ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD
+
 OUI:1C330E*
  ID_OUI_FROM_DATABASE=PernixData
 
@@ -45131,6 +45269,9 @@ OUI:1C4455*
 OUI:1C4593*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:1C45C2*
+ ID_OUI_FROM_DATABASE=Huizhou City Sunsin lntelligent Technology Co.,Ltd
+
 OUI:1C4840*
  ID_OUI_FROM_DATABASE=IMS Messsysteme GmbH
 
@@ -45152,6 +45293,9 @@ OUI:1C4BB9*
 OUI:1C4BD6*
  ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
 
+OUI:1C4C48*
+ ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED
+
 OUI:1C4D66*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
@@ -45572,6 +45716,9 @@ OUI:1C8E8E*
 OUI:1C8F8A*
  ID_OUI_FROM_DATABASE=Phase Motion Control SpA
 
+OUI:1C90BE*
+ ID_OUI_FROM_DATABASE=Ericsson AB
+
 OUI:1C9148*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -45623,6 +45770,9 @@ OUI:1C9E46*
 OUI:1C9ECB*
  ID_OUI_FROM_DATABASE=Beijing Nari Smartchip Microelectronics Company Limited
 
+OUI:1C9F4E*
+ ID_OUI_FROM_DATABASE=COOSEA GROUP (HK) COMPANY LIMITED
+
 OUI:1CA0B8*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd.
 
@@ -45680,6 +45830,9 @@ OUI:1CA532*
 OUI:1CA770*
  ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD
 
+OUI:1CA852*
+ ID_OUI_FROM_DATABASE=SENSAIO PTE LTD
+
 OUI:1CAA07*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -45920,6 +46073,9 @@ OUI:1CE192*
 OUI:1CE2CC*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:1CE57F*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:1CE61D*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -45938,6 +46094,9 @@ OUI:1CEA0B*
 OUI:1CEA1B*
  ID_OUI_FROM_DATABASE=Nokia
 
+OUI:1CEC72*
+ ID_OUI_FROM_DATABASE=Allradio Co., Ltd
+
 OUI:1CEEC9*
  ID_OUI_FROM_DATABASE=Elo touch solutions
 
@@ -46136,6 +46295,9 @@ OUI:20180E*
 OUI:201A06*
  ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD.
 
+OUI:201B88*
+ ID_OUI_FROM_DATABASE=Dongguan Liesheng Electronic Co., Ltd.
+
 OUI:201BC9*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
@@ -46277,6 +46439,9 @@ OUI:204E71*
 OUI:204E7F*
  ID_OUI_FROM_DATABASE=NETGEAR
 
+OUI:204EF6*
+ ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
+
 OUI:2050E7*
  ID_OUI_FROM_DATABASE=AMPAK Technology,Inc.
 
@@ -46461,7 +46626,7 @@ OUI:2085938*
  ID_OUI_FROM_DATABASE=AASSET SECURITY
 
 OUI:2085939*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Mastodon Design
 
 OUI:208593A*
  ID_OUI_FROM_DATABASE=H3 Industries, Inc.
@@ -46580,6 +46745,9 @@ OUI:20AB37*
 OUI:20AB48*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:20AC9C*
+ ID_OUI_FROM_DATABASE=China Telecom Corporation Limited
+
 OUI:20AD56*
  ID_OUI_FROM_DATABASE=Continental Automotive Systems Inc.
 
@@ -46643,6 +46811,9 @@ OUI:20C9D0*
 OUI:20CD39*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:20CD6E*
+ ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd.
+
 OUI:20CEC4*
  ID_OUI_FROM_DATABASE=Peraso Technologies
 
@@ -46691,6 +46862,9 @@ OUI:20DC93*
 OUI:20DCE6*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:20DCFD*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:20DE88*
  ID_OUI_FROM_DATABASE=IC Realtime LLC
 
@@ -46793,6 +46967,9 @@ OUI:2400BA*
 OUI:2400FA*
  ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co., Ltd
 
+OUI:24016F*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:2401C7*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -46805,6 +46982,9 @@ OUI:240588*
 OUI:2405F5*
  ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
 
+OUI:2406AA*
+ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
+
 OUI:240917*
  ID_OUI_FROM_DATABASE=Devlin Electronics Limited
 
@@ -46847,6 +47027,9 @@ OUI:241064*
 OUI:241125*
  ID_OUI_FROM_DATABASE=Hutek Co., Ltd.
 
+OUI:241145*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:241148*
  ID_OUI_FROM_DATABASE=Entropix, LLC
 
@@ -46881,7 +47064,7 @@ OUI:2415107*
  ID_OUI_FROM_DATABASE=SuZhou A-rack Information Technology Co.,Ltd
 
 OUI:2415108*
- ID_OUI_FROM_DATABASE=Medicomp, Inc
+ ID_OUI_FROM_DATABASE=Private
 
 OUI:2415109*
  ID_OUI_FROM_DATABASE=Topgolf Sweden AB
@@ -46964,6 +47147,9 @@ OUI:242E90*
 OUI:242FFA*
  ID_OUI_FROM_DATABASE=Toshiba Global Commerce Solutions
 
+OUI:2430F8*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:243154*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -47138,6 +47324,9 @@ OUI:2462AB*
 OUI:2462CE*
  ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
 
+OUI:24649F*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:2464EF*
  ID_OUI_FROM_DATABASE=CYG SUNRI CO.,LTD.
 
@@ -47189,6 +47378,9 @@ OUI:247260*
 OUI:2474F7*
  ID_OUI_FROM_DATABASE=GoPro
 
+OUI:247625*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:247656*
  ID_OUI_FROM_DATABASE=Shanghai Net Miles Fiber Optics Technology Co., LTD.
 
@@ -47270,6 +47462,15 @@ OUI:2493CA*
 OUI:249442*
  ID_OUI_FROM_DATABASE=OPEN ROAD SOLUTIONS , INC.
 
+OUI:249493*
+ ID_OUI_FROM_DATABASE=FibRSol Global Network Limited
+
+OUI:249494*
+ ID_OUI_FROM_DATABASE=Hong Kong Bouffalo Lab Limited
+
+OUI:2494CB*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:249504*
  ID_OUI_FROM_DATABASE=SFR
 
@@ -47279,6 +47480,9 @@ OUI:2497ED*
 OUI:249EAB*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:249F89*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:24A074*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -47294,6 +47498,9 @@ OUI:24A42C*
 OUI:24A43C*
  ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc.
 
+OUI:24A487*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:24A495*
  ID_OUI_FROM_DATABASE=Thales Canada Inc.
 
@@ -47594,6 +47801,9 @@ OUI:280DFC*
 OUI:280E8B*
  ID_OUI_FROM_DATABASE=Beijing Spirit Technology Development Co., Ltd.
 
+OUI:280FC5*
+ ID_OUI_FROM_DATABASE=Beijing Leadsec Technology Co., Ltd.
+
 OUI:28101B*
  ID_OUI_FROM_DATABASE=MagnaCom
 
@@ -48051,7 +48261,7 @@ OUI:28A02B*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
 OUI:28A183*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:28A186*
  ID_OUI_FROM_DATABASE=enblink
@@ -48086,6 +48296,9 @@ OUI:28AC67*
 OUI:28AC9E*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:28AD18*
+ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD
+
 OUI:28AD3E*
  ID_OUI_FROM_DATABASE=Shenzhen TONG BO WEI Technology CO.,LTD
 
@@ -48254,6 +48467,9 @@ OUI:28CFDA*
 OUI:28CFE9*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:28D044*
+ ID_OUI_FROM_DATABASE=Shenzhen Xinyin technology company
+
 OUI:28D0CB*
  ID_OUI_FROM_DATABASE=Cambridge Communication Systems Ltd
 
@@ -48287,6 +48503,9 @@ OUI:28D997*
 OUI:28DB81*
  ID_OUI_FROM_DATABASE=Shanghai Guao Electronic Technology Co., Ltd
 
+OUI:28DE65*
+ ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
+
 OUI:28DEE5*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -48314,6 +48533,9 @@ OUI:28E34E*
 OUI:28E476*
  ID_OUI_FROM_DATABASE=Pi-Coral
 
+OUI:28E5B0*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:28E608*
  ID_OUI_FROM_DATABASE=Tokheim
 
@@ -48527,6 +48749,9 @@ OUI:2C0623*
 OUI:2C073C*
  ID_OUI_FROM_DATABASE=DEVLINE LIMITED
 
+OUI:2C0786*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:2C081C*
  ID_OUI_FROM_DATABASE=OVH
 
@@ -48911,6 +49136,9 @@ OUI:2C4835D*
 OUI:2C4835E*
  ID_OUI_FROM_DATABASE=IROOTECH TECHNOLOGY CO.,LTD
 
+OUI:2C4A11*
+ ID_OUI_FROM_DATABASE=Ciena Corporation
+
 OUI:2C4CC6*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
@@ -49703,6 +49931,9 @@ OUI:302432*
 OUI:302478*
  ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
 
+OUI:3024A9*
+ ID_OUI_FROM_DATABASE=HP Inc.
+
 OUI:3027CF*
  ID_OUI_FROM_DATABASE=Private
 
@@ -49718,6 +49949,9 @@ OUI:302DE8*
 OUI:30317D*
  ID_OUI_FROM_DATABASE=Hosiden Corporation
 
+OUI:303235*
+ ID_OUI_FROM_DATABASE=Qingdao Intelligent&Precise Electronics Co.,Ltd.
+
 OUI:303294*
  ID_OUI_FROM_DATABASE=W-IE-NE-R Plein & Baus GmbH
 
@@ -49871,6 +50105,9 @@ OUI:3052CB*
 OUI:3055ED*
  ID_OUI_FROM_DATABASE=Trex Network LLC
 
+OUI:305684*
+ ID_OUI_FROM_DATABASE=SHENZHEN YUNJI INTELLIGENT TECHNOLOGY CO.,LTD
+
 OUI:305714*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -50060,9 +50297,15 @@ OUI:309BAD*
 OUI:309C23*
  ID_OUI_FROM_DATABASE=Micro-Star INTL CO., LTD.
 
+OUI:309E1D*
+ ID_OUI_FROM_DATABASE=OHSUNG
+
 OUI:309FFB*
  ID_OUI_FROM_DATABASE=Ardomus Networks Corporation
 
+OUI:30A023*
+ ID_OUI_FROM_DATABASE=ROCK PATH S.R.L
+
 OUI:30A1FA*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -50108,11 +50351,14 @@ OUI:30AEA4*
 OUI:30AEF6*
  ID_OUI_FROM_DATABASE=Radio Mobile Access
 
+OUI:30AFCE*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:30B164*
  ID_OUI_FROM_DATABASE=Power Electronics International Inc.
 
 OUI:30B216*
- ID_OUI_FROM_DATABASE=ABB Power Grids Germany AG – Grid Automation
+ ID_OUI_FROM_DATABASE=Hitachi ABB Power Grids – Grid Automation
 
 OUI:30B237*
  ID_OUI_FROM_DATABASE=GD Midea Air-Conditioning Equipment Co.,Ltd.
@@ -50144,11 +50390,14 @@ OUI:30B7D4*
 OUI:30B9B0*
  ID_OUI_FROM_DATABASE=Intracom Asia Co., Ltd
 
+OUI:30BE3B*
+ ID_OUI_FROM_DATABASE=Mitsubishi Electric Corporation
+
 OUI:30C01B*
  ID_OUI_FROM_DATABASE=Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd
 
 OUI:30C3D9*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:30C507*
  ID_OUI_FROM_DATABASE=ECI Telecom Ltd.
@@ -50177,6 +50426,9 @@ OUI:30CC21*
 OUI:30CDA7*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:30D042*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
 OUI:30D16B*
  ID_OUI_FROM_DATABASE=Liteon Technology Corporation
 
@@ -50204,6 +50456,9 @@ OUI:30D659*
 OUI:30D6C9*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:30D941*
+ ID_OUI_FROM_DATABASE=Raydium Semiconductor Corp.
+
 OUI:30D9D9*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -50219,6 +50474,9 @@ OUI:30E090*
 OUI:30E171*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
+OUI:30E283*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:30E37A*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -50397,7 +50655,7 @@ OUI:34049E8*
  ID_OUI_FROM_DATABASE=Eclipse Information Technologies
 
 OUI:34049E9*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Church & Dwight Co., Inc.
 
 OUI:34049EA*
  ID_OUI_FROM_DATABASE=i3 International Inc.
@@ -50406,7 +50664,7 @@ OUI:34049EB*
  ID_OUI_FROM_DATABASE=Eginity, Inc.
 
 OUI:34049EC*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=ClearCaptions LLC
 
 OUI:34049ED*
  ID_OUI_FROM_DATABASE=uikismart
@@ -50486,6 +50744,9 @@ OUI:341A4C*
 OUI:341B22*
  ID_OUI_FROM_DATABASE=Grandbeing Technology Co., Ltd
 
+OUI:341CF0*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:341E6B*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -50573,6 +50834,9 @@ OUI:3429EA*
 OUI:342AF1*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:342B70*
+ ID_OUI_FROM_DATABASE=Arris
+
 OUI:342CC4*
  ID_OUI_FROM_DATABASE=Compal Broadband Networks, Inc.
 
@@ -51042,7 +51306,7 @@ OUI:34C69A*
  ID_OUI_FROM_DATABASE=Enecsys Ltd
 
 OUI:34C731*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:34C803*
  ID_OUI_FROM_DATABASE=Nokia Corporation
@@ -51131,6 +51395,9 @@ OUI:34D270*
 OUI:34D2C4*
  ID_OUI_FROM_DATABASE=RENA GmbH Print Systeme
 
+OUI:34D693*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:34D712*
  ID_OUI_FROM_DATABASE=Smartisan Digital Co., Ltd
 
@@ -51749,6 +52016,9 @@ OUI:3876D1*
 OUI:387862*
  ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc
 
+OUI:387A3C*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
 OUI:387B47*
  ID_OUI_FROM_DATABASE=AKELA, Inc.
 
@@ -51818,12 +52088,18 @@ OUI:3894ED*
 OUI:389592*
  ID_OUI_FROM_DATABASE=Beijing Tendyron Corporation
 
+OUI:3897A4*
+ ID_OUI_FROM_DATABASE=ELECOM CO.,LTD.
+
 OUI:3897D6*
  ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
 
 OUI:3898D8*
  ID_OUI_FROM_DATABASE=MERITECH CO.,LTD
 
+OUI:3898E9*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:389AF6*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -52017,7 +52293,7 @@ OUI:38BF33*
  ID_OUI_FROM_DATABASE=NEC CASIO Mobile Communications
 
 OUI:38C096*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:38C2BA*
  ID_OUI_FROM_DATABASE=CCTV NEOTECH
@@ -52040,6 +52316,9 @@ OUI:38C986*
 OUI:38C9A9*
  ID_OUI_FROM_DATABASE=SMART High Reliability Solutions, Inc.
 
+OUI:38CA73*
+ ID_OUI_FROM_DATABASE=Shenzhen MiaoMing  Intelligent Technology Co.,Ltd
+
 OUI:38CA97*
  ID_OUI_FROM_DATABASE=Contour Design LLC
 
@@ -52247,6 +52526,9 @@ OUI:38FACA*
 OUI:38FB14*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:38FC98*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:38FDFE0*
  ID_OUI_FROM_DATABASE=Edge I&D Co., Ltd.
 
@@ -52712,6 +52994,9 @@ OUI:3C5F01*
 OUI:3C6104*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:3C6105*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:3C6200*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -52970,6 +53255,9 @@ OUI:3CA31A*
 OUI:3CA348*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
+OUI:3CA37E*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:3CA581*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
@@ -53036,6 +53324,9 @@ OUI:3CBBFD*
 OUI:3CBD3E*
  ID_OUI_FROM_DATABASE=Beijing Xiaomi Electronics Co., Ltd.
 
+OUI:3CBDC5*
+ ID_OUI_FROM_DATABASE=Arcadyan Corporation
+
 OUI:3CBDD8*
  ID_OUI_FROM_DATABASE=LG ELECTRONICS INC
 
@@ -53099,6 +53390,9 @@ OUI:3CD0F8*
 OUI:3CD16E*
  ID_OUI_FROM_DATABASE=Telepower Communication Co., Ltd
 
+OUI:3CD2E5*
+ ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
+
 OUI:3CD4D6*
  ID_OUI_FROM_DATABASE=WirelessWERX, Inc
 
@@ -53132,6 +53426,9 @@ OUI:3CDFA9*
 OUI:3CDFBD*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:3CE038*
+ ID_OUI_FROM_DATABASE=Plumeria Networks, Inc.
+
 OUI:3CE072*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -53351,6 +53648,9 @@ OUI:4012E4*
 OUI:4013D9*
  ID_OUI_FROM_DATABASE=Global ES
 
+OUI:4014AD*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:401597*
  ID_OUI_FROM_DATABASE=Protect America, Inc.
 
@@ -53381,6 +53681,9 @@ OUI:401920*
 OUI:401B5F*
  ID_OUI_FROM_DATABASE=WEIFANG GOERTEK ELECTRONICS CO.,LTD
 
+OUI:401C83*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:401D59*
  ID_OUI_FROM_DATABASE=Biometric Associates, LP
 
@@ -53762,6 +54065,9 @@ OUI:408B07*
 OUI:408BF6*
  ID_OUI_FROM_DATABASE=Shenzhen TCL New Technology Co., Ltd
 
+OUI:408C4C*
+ ID_OUI_FROM_DATABASE=Shenzhen MiaoMing  Intelligent Technology Co.,Ltd
+
 OUI:408D5C*
  ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD.
 
@@ -53885,6 +54191,9 @@ OUI:40A8F0*
 OUI:40A93F*
  ID_OUI_FROM_DATABASE=Pivotal Commware, Inc.
 
+OUI:40A9CF*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:40AA56*
  ID_OUI_FROM_DATABASE=China Dragon Technology Limited
 
@@ -53924,6 +54233,9 @@ OUI:40B4CD*
 OUI:40B4F0*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:40B5C1*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:40B688*
  ID_OUI_FROM_DATABASE=LEGIC Identsystems AG
 
@@ -54026,6 +54338,9 @@ OUI:40D3AE*
 OUI:40D40E*
  ID_OUI_FROM_DATABASE=Biodata Ltd
 
+OUI:40D4BD*
+ ID_OUI_FROM_DATABASE=SK Networks Service CO., LTD.
+
 OUI:40D559*
  ID_OUI_FROM_DATABASE=MICRO S.E.R.I.
 
@@ -54434,6 +54749,9 @@ OUI:443839*
 OUI:4439C4*
  ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd.
 
+OUI:443B32*
+ ID_OUI_FROM_DATABASE=Intelbras
+
 OUI:443C88*
  ID_OUI_FROM_DATABASE=FICOSA MAROC INTERNATIONAL
 
@@ -54857,6 +55175,9 @@ OUI:44CB8B*
 OUI:44CD0E*
  ID_OUI_FROM_DATABASE=FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.
 
+OUI:44CE3A*
+ ID_OUI_FROM_DATABASE=Jiangsu Huacun Electronic Technology Co., Ltd.
+
 OUI:44CE7D*
  ID_OUI_FROM_DATABASE=SFR
 
@@ -54986,6 +55307,9 @@ OUI:44E6B0*
 OUI:44E8A5*
  ID_OUI_FROM_DATABASE=Myreka Technologies Sdn. Bhd.
 
+OUI:44E968*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:44E9DD*
  ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
 
@@ -55016,6 +55340,9 @@ OUI:44EFCF*
 OUI:44F034*
  ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD.
 
+OUI:44F21B*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:44F436*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -55169,6 +55496,9 @@ OUI:48216C*
 OUI:482335*
  ID_OUI_FROM_DATABASE=Dialog Semiconductor Hellas SA
 
+OUI:482567*
+ ID_OUI_FROM_DATABASE=Poly
+
 OUI:48262C*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -55412,6 +55742,9 @@ OUI:486EFB*
 OUI:486FD2*
  ID_OUI_FROM_DATABASE=StorSimple Inc
 
+OUI:48701E*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:487119*
  ID_OUI_FROM_DATABASE=SGB GROUP LTD.
 
@@ -55487,6 +55820,9 @@ OUI:4889E7*
 OUI:488AD2*
  ID_OUI_FROM_DATABASE=MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.
 
+OUI:488B0A*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:488D36*
  ID_OUI_FROM_DATABASE=Arcadyan Corporation
 
@@ -55559,6 +55895,9 @@ OUI:48A472*
 OUI:48A493*
  ID_OUI_FROM_DATABASE=TAIYO YUDEN CO.,LTD
 
+OUI:48A516*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:48A5E7*
  ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd
 
@@ -55703,6 +56042,9 @@ OUI:48D855*
 OUI:48D875*
  ID_OUI_FROM_DATABASE=China TransInfo Technology Co., Ltd
 
+OUI:48D890*
+ ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED
+
 OUI:48D8FE*
  ID_OUI_FROM_DATABASE=ClarIDy Solutions, Inc.
 
@@ -55775,11 +56117,14 @@ OUI:48EE0C*
 OUI:48EE86*
  ID_OUI_FROM_DATABASE=UTStarcom (China) Co.,Ltd
 
+OUI:48EF61*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:48F027*
  ID_OUI_FROM_DATABASE=Chengdu newifi Co.,Ltd
 
 OUI:48F07B*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:48F17F*
  ID_OUI_FROM_DATABASE=Intel Corporate
@@ -55835,6 +56180,9 @@ OUI:4C0082*
 OUI:4C0143*
  ID_OUI_FROM_DATABASE=eero inc.
 
+OUI:4C0220*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:4C022E*
  ID_OUI_FROM_DATABASE=CMR KOREA CO., LTD
 
@@ -55928,6 +56276,9 @@ OUI:4C1D96*
 OUI:4C1FCC*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:4C20B8*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:4C2113*
  ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
 
@@ -56003,6 +56354,9 @@ OUI:4C3910*
 OUI:4C3B74*
  ID_OUI_FROM_DATABASE=VOGTEC(H.K.) Co., Ltd
 
+OUI:4C3BDF*
+ ID_OUI_FROM_DATABASE=Microsoft Corporation
+
 OUI:4C3C16*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -56090,6 +56444,9 @@ OUI:4C5077*
 OUI:4C5262*
  ID_OUI_FROM_DATABASE=Fujitsu Technology Solutions GmbH
 
+OUI:4C52EC*
+ ID_OUI_FROM_DATABASE=SOLARWATT GmbH
+
 OUI:4C5427*
  ID_OUI_FROM_DATABASE=Linepro Sp. z o.o.
 
@@ -56198,6 +56555,9 @@ OUI:4C6BE8*
 OUI:4C6C13*
  ID_OUI_FROM_DATABASE=IoT Company Solucoes Tecnologicas Ltda
 
+OUI:4C6D58*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
 OUI:4C6E6E*
  ID_OUI_FROM_DATABASE=Comnect Technology CO.,LTD
 
@@ -56747,6 +57107,9 @@ OUI:4CEDFB*
 OUI:4CEEB0*
  ID_OUI_FROM_DATABASE=SHC Netzwerktechnik GmbH
 
+OUI:4CEF56*
+ ID_OUI_FROM_DATABASE=Shenzhen Sundray Technologies Company Limited
+
 OUI:4CEFC0*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
@@ -56780,6 +57143,9 @@ OUI:4CFACA*
 OUI:4CFB45*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:4CFBF4*
+ ID_OUI_FROM_DATABASE=Optimal Audio Ltd
+
 OUI:4CFBFE*
  ID_OUI_FROM_DATABASE=Sercomm Japan Corporation
 
@@ -56981,6 +57347,9 @@ OUI:502E5C*
 OUI:502ECE*
  ID_OUI_FROM_DATABASE=Asahi Electronics Co.,Ltd
 
+OUI:502F9B*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:502FA8*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -57329,6 +57698,9 @@ OUI:508CF5*
 OUI:508D6F*
  ID_OUI_FROM_DATABASE=CHAHOO Limited
 
+OUI:508E49*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:508F4C*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -57431,6 +57803,9 @@ OUI:50A4D0D*
 OUI:50A4D0E*
  ID_OUI_FROM_DATABASE=Sagetech Corporation
 
+OUI:50A5DC*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:50A67F*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -58235,6 +58610,9 @@ OUI:549F35*
 OUI:549FAE*
  ID_OUI_FROM_DATABASE=iBASE Gaming Inc
 
+OUI:549FC6*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:54A04F*
  ID_OUI_FROM_DATABASE=t-mac Technologies Ltd
 
@@ -58581,7 +58959,7 @@ OUI:581626*
  ID_OUI_FROM_DATABASE=Avaya Inc
 
 OUI:5816D7*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:58170C*
  ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc
@@ -58610,15 +58988,45 @@ OUI:581FEF*
 OUI:582059*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
+OUI:58208A0*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
+OUI:58208A2*
+ ID_OUI_FROM_DATABASE=MARS DIGI TECH CO .,LTD
+
+OUI:58208A3*
+ ID_OUI_FROM_DATABASE=Aggregate Co.,Ltd.
+
 OUI:58208A4*
  ID_OUI_FROM_DATABASE=TRING
 
+OUI:58208A5*
+ ID_OUI_FROM_DATABASE=JIA HUANG JHAN YE CO.,LTD
+
+OUI:58208A6*
+ ID_OUI_FROM_DATABASE=Shangyin Intelligence Technology Shandong Co.,Ltd
+
+OUI:58208A7*
+ ID_OUI_FROM_DATABASE=pureLiFi Ltd
+
 OUI:58208A8*
  ID_OUI_FROM_DATABASE=SAMIL CTS Co., Ltd.
 
 OUI:58208A9*
  ID_OUI_FROM_DATABASE=Suzhou Ruilisi Technology Ltd.
 
+OUI:58208AA*
+ ID_OUI_FROM_DATABASE=Conductix-Wampfler
+
+OUI:58208AB*
+ ID_OUI_FROM_DATABASE=Infodev Electronic Designers Intl.
+
+OUI:58208AD*
+ ID_OUI_FROM_DATABASE=SAMBO HITECH
+
+OUI:58208AE*
+ ID_OUI_FROM_DATABASE=UPM Technology, Inc
+
 OUI:5820B1*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
@@ -58631,6 +59039,9 @@ OUI:5821E9*
 OUI:58238C*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
+OUI:582429*
+ ID_OUI_FROM_DATABASE=Google, Inc.
+
 OUI:582575*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -58757,6 +59168,9 @@ OUI:585FF6*
 OUI:58605F*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:5860D8*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:586163*
  ID_OUI_FROM_DATABASE=Quantum Networks (SG) Pte. Ltd.
 
@@ -58856,6 +59270,9 @@ OUI:5885A2*
 OUI:5885E9*
  ID_OUI_FROM_DATABASE=Realme Chongqing MobileTelecommunications Corp Ltd
 
+OUI:588694*
+ ID_OUI_FROM_DATABASE=EFM Networks
+
 OUI:58874C*
  ID_OUI_FROM_DATABASE=LITE-ON CLEAN ENERGY TECHNOLOGY CORP.
 
@@ -58904,6 +59321,51 @@ OUI:5894B2*
 OUI:5894CF*
  ID_OUI_FROM_DATABASE=Vertex Standard LMR, Inc.
 
+OUI:5895D80*
+ ID_OUI_FROM_DATABASE=Shenzhen DOOGEE Hengtong Technology CO.,LTD
+
+OUI:5895D81*
+ ID_OUI_FROM_DATABASE=shenzhen UDD Technologies,co.,Ltd
+
+OUI:5895D82*
+ ID_OUI_FROM_DATABASE=Sercomm Corporation.
+
+OUI:5895D83*
+ ID_OUI_FROM_DATABASE=Tonnet Telecommunication International Co., Ltd.
+
+OUI:5895D84*
+ ID_OUI_FROM_DATABASE=Unity Surveillance, Inc.
+
+OUI:5895D85*
+ ID_OUI_FROM_DATABASE=elgris UG
+
+OUI:5895D86*
+ ID_OUI_FROM_DATABASE=Norgren Manufacturing Co., Ltd.
+
+OUI:5895D87*
+ ID_OUI_FROM_DATABASE=Epiphan Systems Inc
+
+OUI:5895D88*
+ ID_OUI_FROM_DATABASE=Shenzhen C & D Electronics Co., Ltd.
+
+OUI:5895D89*
+ ID_OUI_FROM_DATABASE=Loftie
+
+OUI:5895D8A*
+ ID_OUI_FROM_DATABASE=Peak Communications Limited
+
+OUI:5895D8B*
+ ID_OUI_FROM_DATABASE=SuZhou Ruishengwei Intelligent Technology Co.,Ltd
+
+OUI:5895D8C*
+ ID_OUI_FROM_DATABASE=LOCTEK ERGONOMIC TECHNOLOGY CORP.
+
+OUI:5895D8D*
+ ID_OUI_FROM_DATABASE=Alunos AG
+
+OUI:5895D8E*
+ ID_OUI_FROM_DATABASE=Gmv sistemas SAU
+
 OUI:58961D*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -59042,6 +59504,9 @@ OUI:58D071*
 OUI:58D08F*
  ID_OUI_FROM_DATABASE=IEEE 1904.1 Working Group
 
+OUI:58D349*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:58D50A*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
@@ -59103,7 +59568,7 @@ OUI:58E873*
  ID_OUI_FROM_DATABASE=HANGZHOU DANGBEI NETWORK TECH.Co.,Ltd
 
 OUI:58E8760*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Zhuhai Raysharp Technology Co.,Ltd
 
 OUI:58E8761*
  ID_OUI_FROM_DATABASE=Beijing Perabytes IS Technology Co., Ltd
@@ -59294,6 +59759,9 @@ OUI:5C0E8B*
 OUI:5C0FFB*
  ID_OUI_FROM_DATABASE=Amino Communications Ltd
 
+OUI:5C10C5*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:5C1193*
  ID_OUI_FROM_DATABASE=Seal One AG
 
@@ -59385,7 +59853,7 @@ OUI:5C338E*
  ID_OUI_FROM_DATABASE=Alpha Networks Inc.
 
 OUI:5C3400*
- ID_OUI_FROM_DATABASE=HISENSE VISUAL TECHNOLOGY CO.,LTD
+ ID_OUI_FROM_DATABASE=Hisense Electric Co.,Ltd
 
 OUI:5C353B*
  ID_OUI_FROM_DATABASE=Compal Broadband Networks, Inc.
@@ -59498,6 +59966,9 @@ OUI:5C5EAB*
 OUI:5C5F67*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:5C6199*
+ ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.
+
 OUI:5C63BF*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
@@ -59636,6 +60107,9 @@ OUI:5C865C*
 OUI:5C86C1*
  ID_OUI_FROM_DATABASE=DONGGUAN SOLUM ELECTRONICS CO.,LTD
 
+OUI:5C8730*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:5C8778*
  ID_OUI_FROM_DATABASE=Cybertelbridge co.,ltd
 
@@ -59795,6 +60269,9 @@ OUI:5CBAEF*
 OUI:5CBD9E*
  ID_OUI_FROM_DATABASE=HONGKONG MIRACLE EAGLE TECHNOLOGY(GROUP) LIMITED
 
+OUI:5CC0A0*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:5CC1D7*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -59948,6 +60425,9 @@ OUI:5CEB4E*
 OUI:5CEB68*
  ID_OUI_FROM_DATABASE=Cheerstar Technology Co., Ltd
 
+OUI:5CED8C*
+ ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise
+
 OUI:5CEE79*
  ID_OUI_FROM_DATABASE=Global Digitech Co LTD
 
@@ -60041,9 +60521,15 @@ OUI:5CF9DD*
 OUI:5CF9F0*
  ID_OUI_FROM_DATABASE=Atomos Engineering P/L
 
+OUI:5CF9FD*
+ ID_OUI_FROM_DATABASE=Taicang T&W Electronics
+
 OUI:5CFAFB*
  ID_OUI_FROM_DATABASE=Acubit
 
+OUI:5CFB3A*
+ ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
+
 OUI:5CFB7C*
  ID_OUI_FROM_DATABASE=Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd
 
@@ -60209,6 +60695,9 @@ OUI:60334B*
 OUI:603553*
  ID_OUI_FROM_DATABASE=Buwon Technology
 
+OUI:603573*
+ ID_OUI_FROM_DATABASE=Earda Technologies co Ltd
+
 OUI:6035C0*
  ID_OUI_FROM_DATABASE=SFR
 
@@ -60219,7 +60708,7 @@ OUI:6036DD*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
 OUI:60380E*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:6038E0*
  ID_OUI_FROM_DATABASE=Belkin International Inc.
@@ -60230,6 +60719,9 @@ OUI:60391F*
 OUI:603A7C*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:603CEE*
+ ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
+
 OUI:603D26*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
@@ -60362,6 +60854,9 @@ OUI:606DC7*
 OUI:606ED0*
  ID_OUI_FROM_DATABASE=SEAL AG
 
+OUI:607072*
+ ID_OUI_FROM_DATABASE=SHENZHEN HONGDE SMART LINK TECHNOLOGY CO., LTD
+
 OUI:6070C0*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -60386,6 +60881,9 @@ OUI:607771*
 OUI:6077E2*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:607EA4*
+ ID_OUI_FROM_DATABASE=Shanghai Imilab Technology Co.Ltd
+
 OUI:607EC9*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -60396,7 +60894,7 @@ OUI:607EDD*
  ID_OUI_FROM_DATABASE=Microsoft Mobile Oy
 
 OUI:60812B*
- ID_OUI_FROM_DATABASE=Custom Control Concepts
+ ID_OUI_FROM_DATABASE=Astronics Custom Control Concepts
 
 OUI:6081F9*
  ID_OUI_FROM_DATABASE=Helium Systems, Inc
@@ -60632,6 +61130,9 @@ OUI:60BD91*
 OUI:60BEB5*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
+OUI:60BEC4*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:60C0BF*
  ID_OUI_FROM_DATABASE=ON Semiconductor
 
@@ -60773,6 +61274,9 @@ OUI:60DA83*
 OUI:60DB2A*
  ID_OUI_FROM_DATABASE=HNS
 
+OUI:60DB98*
+ ID_OUI_FROM_DATABASE=Calix Inc.
+
 OUI:60DE35*
  ID_OUI_FROM_DATABASE=GITSN, Inc.
 
@@ -60896,6 +61400,9 @@ OUI:6400F1*
 OUI:6402CB*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:64037F*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:6405BE*
  ID_OUI_FROM_DATABASE=NEW LIGHT LED
 
@@ -60983,6 +61490,9 @@ OUI:64200C*
 OUI:64209F*
  ID_OUI_FROM_DATABASE=Tilgin AB
 
+OUI:6420E0*
+ ID_OUI_FROM_DATABASE=T3 Technology Co., Ltd.
+
 OUI:642184*
  ID_OUI_FROM_DATABASE=Nippon Denki Kagaku Co.,LTD
 
@@ -61316,6 +61826,9 @@ OUI:64777D*
 OUI:647791*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:647924*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:6479A7*
  ID_OUI_FROM_DATABASE=Phison Electronics Corp.
 
@@ -61409,9 +61922,15 @@ OUI:649FF7*
 OUI:64A0E7*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:64A200*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:64A232*
  ID_OUI_FROM_DATABASE=OOO Samlight
 
+OUI:64A28A*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:64A2F9*
  ID_OUI_FROM_DATABASE=OnePlus Technology (Shenzhen) Co., Ltd
 
@@ -61560,7 +62079,7 @@ OUI:64D2C4*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
 OUI:64D4BD*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:64D4DA*
  ID_OUI_FROM_DATABASE=Intel Corporate
@@ -61901,6 +62420,9 @@ OUI:683C7D*
 OUI:683E02*
  ID_OUI_FROM_DATABASE=SIEMENS AG, Digital Factory, Motion Control System
 
+OUI:683E26*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:683E34*
  ID_OUI_FROM_DATABASE=MEIZU Technology Co., Ltd.
 
@@ -61916,6 +62438,9 @@ OUI:684352*
 OUI:6843D7*
  ID_OUI_FROM_DATABASE=Agilecom Photonics Solutions Guangdong Limited
 
+OUI:684571*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:6845F1*
  ID_OUI_FROM_DATABASE=TOSHIBA CLIENT SOLUTIONS CO., LTD.
 
@@ -62027,6 +62552,9 @@ OUI:686E48*
 OUI:687251*
  ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc.
 
+OUI:6872C3*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:6872DC*
  ID_OUI_FROM_DATABASE=CETORY.TV Company Limited
 
@@ -62039,6 +62567,51 @@ OUI:687848*
 OUI:68784C*
  ID_OUI_FROM_DATABASE=Nortel Networks
 
+OUI:6879120*
+ ID_OUI_FROM_DATABASE=PCTEL, Inc.
+
+OUI:6879121*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
+OUI:6879122*
+ ID_OUI_FROM_DATABASE=CNDI CO.,LTD
+
+OUI:6879123*
+ ID_OUI_FROM_DATABASE=Stephan Electronics SARL
+
+OUI:6879124*
+ ID_OUI_FROM_DATABASE=McDonald's Corporation
+
+OUI:6879125*
+ ID_OUI_FROM_DATABASE=Copper Labs, Inc.
+
+OUI:6879126*
+ ID_OUI_FROM_DATABASE=APPOTRONICS CO., LTD
+
+OUI:6879127*
+ ID_OUI_FROM_DATABASE=Babbit and Friends, SIA
+
+OUI:6879128*
+ ID_OUI_FROM_DATABASE=ShangHai Aigentoo Information Technology Co., Ltd
+
+OUI:6879129*
+ ID_OUI_FROM_DATABASE=LEAPS s.r.o.
+
+OUI:687912A*
+ ID_OUI_FROM_DATABASE=Wingtech Mobile Communications Co., Ltd.
+
+OUI:687912B*
+ ID_OUI_FROM_DATABASE=Swisscom Broadcast Ltd
+
+OUI:687912C*
+ ID_OUI_FROM_DATABASE=Globus Infocom Limited
+
+OUI:687912D*
+ ID_OUI_FROM_DATABASE=Neurolab
+
+OUI:687912E*
+ ID_OUI_FROM_DATABASE=Ametek Solidstate Controls
+
 OUI:687924*
  ID_OUI_FROM_DATABASE=ELS-GmbH & Co. KG
 
@@ -62339,6 +62912,9 @@ OUI:68D247*
 OUI:68D482*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT
 
+OUI:68D48B*
+ ID_OUI_FROM_DATABASE=Hailo Technologies Ltd.
+
 OUI:68D6ED*
  ID_OUI_FROM_DATABASE=GooWi Wireless Technology Co., Limited
 
@@ -62471,6 +63047,9 @@ OUI:6C06D6*
 OUI:6C090A*
  ID_OUI_FROM_DATABASE=GEMATICA SRL
 
+OUI:6C09BF*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
 OUI:6C09D6*
  ID_OUI_FROM_DATABASE=Digiquest Electronics LTD
 
@@ -62480,6 +63059,9 @@ OUI:6C0B84*
 OUI:6C0D34*
  ID_OUI_FROM_DATABASE=Nokia
 
+OUI:6C0DC4*
+ ID_OUI_FROM_DATABASE=Beijing Xiaomi Electronics Co., Ltd.
+
 OUI:6C0E0D*
  ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc
 
@@ -62489,6 +63071,12 @@ OUI:6C0EE6*
 OUI:6C0F6A*
  ID_OUI_FROM_DATABASE=JDC Tech Co., Ltd.
 
+OUI:6C1414*
+ ID_OUI_FROM_DATABASE=BUJEON ELECTRONICS Co,.Ltd
+
+OUI:6C146E*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:6C14F7*
  ID_OUI_FROM_DATABASE=Erhardt+Leimer GmbH
 
@@ -62510,6 +63098,9 @@ OUI:6C198F*
 OUI:6C19C0*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:6C1A75*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:6C1C71*
  ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd.
 
@@ -62522,6 +63113,9 @@ OUI:6C1E70*
 OUI:6C1E90*
  ID_OUI_FROM_DATABASE=Hansol Technics Co., Ltd.
 
+OUI:6C1ED7*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:6C2056*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -62567,6 +63161,9 @@ OUI:6C2C06*
 OUI:6C2CDC*
  ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd
 
+OUI:6C2D24*
+ ID_OUI_FROM_DATABASE=Zhen Shi Information Technology (Shanghai) Co., Ltd.
+
 OUI:6C2E33*
  ID_OUI_FROM_DATABASE=Accelink Technologies Co.,Ltd.
 
@@ -62819,6 +63416,9 @@ OUI:6C72E7*
 OUI:6C750D*
  ID_OUI_FROM_DATABASE=WiFiSONG
 
+OUI:6C7637*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:6C7660*
  ID_OUI_FROM_DATABASE=KYOCERA CORPORATION
 
@@ -62903,6 +63503,9 @@ OUI:6C9CED*
 OUI:6C9E7C*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
+OUI:6CA0B4*
+ ID_OUI_FROM_DATABASE=BSkyB Ltd
+
 OUI:6CA100*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -62960,6 +63563,9 @@ OUI:6CAC60*
 OUI:6CAD3F*
  ID_OUI_FROM_DATABASE=Hubbell Building Automation, Inc.
 
+OUI:6CADAD*
+ ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
+
 OUI:6CADEF*
  ID_OUI_FROM_DATABASE=KZ Broadband Technologies, Ltd.
 
@@ -63005,6 +63611,9 @@ OUI:6CB749*
 OUI:6CB7F4*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:6CB881*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:6CB9C5*
  ID_OUI_FROM_DATABASE=Delta Networks, Inc.
 
@@ -63149,6 +63758,9 @@ OUI:6CE85C*
 OUI:6CE873*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:6CE874*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:6CE8C6*
  ID_OUI_FROM_DATABASE=Earda Technologies co Ltd
 
@@ -63410,6 +64022,9 @@ OUI:7038EE*
 OUI:703A0E*
  ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
 
+OUI:703A2D*
+ ID_OUI_FROM_DATABASE=Shenzhen V-Link Technology CO., LTD.
+
 OUI:703A51*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -63440,6 +64055,9 @@ OUI:703D15*
 OUI:703EAC*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:7040FF*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:7041B7*
  ID_OUI_FROM_DATABASE=Edwards Lifesciences LLC
 
@@ -63821,6 +64439,9 @@ OUI:708D09*
 OUI:708F47*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
+OUI:7090B7*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:70918F*
  ID_OUI_FROM_DATABASE=Weber-Stephen Products LLC
 
@@ -63908,6 +64529,9 @@ OUI:70B035*
 OUI:70B08C*
  ID_OUI_FROM_DATABASE=Shenou Communication Equipment Co.,Ltd
 
+OUI:70B13D*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:70B14E*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -63983,6 +64607,9 @@ OUI:70B3D5016*
 OUI:70B3D5017*
  ID_OUI_FROM_DATABASE=FTG Corporation
 
+OUI:70B3D5018*
+ ID_OUI_FROM_DATABASE=DELITECH GROUP
+
 OUI:70B3D5019*
  ID_OUI_FROM_DATABASE=Transit Solutions, LLC.
 
@@ -64361,6 +64988,9 @@ OUI:70B3D509A*
 OUI:70B3D509B*
  ID_OUI_FROM_DATABASE=Jacarta Ltd
 
+OUI:70B3D509C*
+ ID_OUI_FROM_DATABASE=Cardinal Kinetic
+
 OUI:70B3D509D*
  ID_OUI_FROM_DATABASE=PuS GmbH und Co. KG
 
@@ -64619,6 +65249,9 @@ OUI:70B3D50F3*
 OUI:70B3D50F4*
  ID_OUI_FROM_DATABASE=Visual Robotics
 
+OUI:70B3D50F5*
+ ID_OUI_FROM_DATABASE=Season Electronics Ltd
+
 OUI:70B3D50F6*
  ID_OUI_FROM_DATABASE=KSE GmbH
 
@@ -64679,6 +65312,9 @@ OUI:70B3D5109*
 OUI:70B3D510A*
  ID_OUI_FROM_DATABASE=SEASON DESIGN TECHNOLOGY
 
+OUI:70B3D510B*
+ ID_OUI_FROM_DATABASE=SECUREAN CO.,Ltd
+
 OUI:70B3D510C*
  ID_OUI_FROM_DATABASE=Vocality International Ltd
 
@@ -64709,9 +65345,15 @@ OUI:70B3D5114*
 OUI:70B3D5115*
  ID_OUI_FROM_DATABASE=Welltec Corp.
 
+OUI:70B3D5116*
+ ID_OUI_FROM_DATABASE=Momentum Data Systems
+
 OUI:70B3D5117*
  ID_OUI_FROM_DATABASE=SysCom Automationstechnik GmbH
 
+OUI:70B3D5118*
+ ID_OUI_FROM_DATABASE=Macromatic Industrial Controls, Inc.
+
 OUI:70B3D5119*
  ID_OUI_FROM_DATABASE=Private
 
@@ -64886,6 +65528,9 @@ OUI:70B3D5154*
 OUI:70B3D5155*
  ID_OUI_FROM_DATABASE=Sanwa New Tec Co.,Ltd
 
+OUI:70B3D5156*
+ ID_OUI_FROM_DATABASE=Rivercity Innovations Ltd.
+
 OUI:70B3D5157*
  ID_OUI_FROM_DATABASE=Shanghai Jupper Technology Co.Ltd
 
@@ -64973,6 +65618,9 @@ OUI:70B3D5174*
 OUI:70B3D5175*
  ID_OUI_FROM_DATABASE=Akribis Systems
 
+OUI:70B3D5176*
+ ID_OUI_FROM_DATABASE=Larraioz Elektronika
+
 OUI:70B3D5177*
  ID_OUI_FROM_DATABASE=Wired Broadcast Ltd
 
@@ -65063,6 +65711,9 @@ OUI:70B3D5193*
 OUI:70B3D5194*
  ID_OUI_FROM_DATABASE=Husty M.Styczen J.Hupert Sp.J.
 
+OUI:70B3D5195*
+ ID_OUI_FROM_DATABASE=Ci4Rail
+
 OUI:70B3D5197*
  ID_OUI_FROM_DATABASE=Lattech Systems Pty Ltd
 
@@ -65090,6 +65741,9 @@ OUI:70B3D51A0*
 OUI:70B3D51A1*
  ID_OUI_FROM_DATABASE=HMicro Inc
 
+OUI:70B3D51A2*
+ ID_OUI_FROM_DATABASE=Xirgo Technologies LLC
+
 OUI:70B3D51A3*
  ID_OUI_FROM_DATABASE=Telairity Semiconductor
 
@@ -65150,6 +65804,9 @@ OUI:70B3D51B8*
 OUI:70B3D51B9*
  ID_OUI_FROM_DATABASE=RELISTE Ges.m.b.H.
 
+OUI:70B3D51BA*
+ ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd.
+
 OUI:70B3D51BB*
  ID_OUI_FROM_DATABASE=EFENTO T P SZYDŁOWSKI K ZARĘBA SPÓŁKA JAWNA
 
@@ -65507,6 +66164,9 @@ OUI:70B3D523B*
 OUI:70B3D523C*
  ID_OUI_FROM_DATABASE=Quasonix, LLC
 
+OUI:70B3D523D*
+ ID_OUI_FROM_DATABASE=Circle Consult ApS
+
 OUI:70B3D523E*
  ID_OUI_FROM_DATABASE=Tornado Modular Systems
 
@@ -65534,6 +66194,9 @@ OUI:70B3D5245*
 OUI:70B3D5246*
  ID_OUI_FROM_DATABASE=Saline Lectronics, Inc.
 
+OUI:70B3D5247*
+ ID_OUI_FROM_DATABASE=Satsky Communication Equipment Co.,Ltd.
+
 OUI:70B3D5248*
  ID_OUI_FROM_DATABASE=GL TECH CO.,LTD
 
@@ -65597,6 +66260,9 @@ OUI:70B3D525C*
 OUI:70B3D525D*
  ID_OUI_FROM_DATABASE=Mimo Networks
 
+OUI:70B3D525E*
+ ID_OUI_FROM_DATABASE=RFHIC
+
 OUI:70B3D525F*
  ID_OUI_FROM_DATABASE=COPPERNIC SAS
 
@@ -65675,6 +66341,9 @@ OUI:70B3D5279*
 OUI:70B3D527A*
  ID_OUI_FROM_DATABASE=TD ECOPHISIKA
 
+OUI:70B3D527B*
+ ID_OUI_FROM_DATABASE=DAVE SRL
+
 OUI:70B3D527C*
  ID_OUI_FROM_DATABASE=MOTION LIB,Inc.
 
@@ -65954,6 +66623,9 @@ OUI:70B3D52DD*
 OUI:70B3D52DE*
  ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
 
+OUI:70B3D52DF*
+ ID_OUI_FROM_DATABASE=EASTERN SCIENCE & TECHNOLOGY CO., LTD
+
 OUI:70B3D52E0*
  ID_OUI_FROM_DATABASE=Peter Huber
 
@@ -66125,6 +66797,9 @@ OUI:70B3D5320*
 OUI:70B3D5321*
  ID_OUI_FROM_DATABASE=Yite technology
 
+OUI:70B3D5322*
+ ID_OUI_FROM_DATABASE=PuS GmbH und Co. KG
+
 OUI:70B3D5323*
  ID_OUI_FROM_DATABASE=TATTILE SRL
 
@@ -66287,6 +66962,9 @@ OUI:70B3D5359*
 OUI:70B3D535A*
  ID_OUI_FROM_DATABASE=Applied Radar, Inc.
 
+OUI:70B3D535B*
+ ID_OUI_FROM_DATABASE=Nuance Hearing Ltd.
+
 OUI:70B3D535C*
  ID_OUI_FROM_DATABASE=ACS electronics srl
 
@@ -66360,7 +67038,7 @@ OUI:70B3D5375*
  ID_OUI_FROM_DATABASE=Adel System srl
 
 OUI:70B3D5376*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Magenta Labs, Inc.
 
 OUI:70B3D5377*
  ID_OUI_FROM_DATABASE=Monnit Corporation
@@ -66389,6 +67067,9 @@ OUI:70B3D537E*
 OUI:70B3D537F*
  ID_OUI_FROM_DATABASE=IDS Innomic GmbH
 
+OUI:70B3D5380*
+ ID_OUI_FROM_DATABASE=SeaTech Intelligent Technology (Shanghai) Co., LTD
+
 OUI:70B3D5381*
  ID_OUI_FROM_DATABASE=CRDE
 
@@ -66443,6 +67124,9 @@ OUI:70B3D5393*
 OUI:70B3D5394*
  ID_OUI_FROM_DATABASE=Romteck Australia
 
+OUI:70B3D5395*
+ ID_OUI_FROM_DATABASE=ICsec S.A.
+
 OUI:70B3D5396*
  ID_OUI_FROM_DATABASE=CTG sp. z o. o.
 
@@ -66473,6 +67157,9 @@ OUI:70B3D53A0*
 OUI:70B3D53A1*
  ID_OUI_FROM_DATABASE=Reckeen HDP Media sp. z o.o. sp. k.
 
+OUI:70B3D53A2*
+ ID_OUI_FROM_DATABASE=Daifuku CO., Ltd.
+
 OUI:70B3D53A3*
  ID_OUI_FROM_DATABASE=CDS Institute of Management Strategy, Inc.
 
@@ -66482,6 +67169,9 @@ OUI:70B3D53A4*
 OUI:70B3D53A5*
  ID_OUI_FROM_DATABASE=KMtronic ltd
 
+OUI:70B3D53A6*
+ ID_OUI_FROM_DATABASE=myenergi Ltd
+
 OUI:70B3D53A7*
  ID_OUI_FROM_DATABASE=Varikorea
 
@@ -66494,6 +67184,9 @@ OUI:70B3D53A9*
 OUI:70B3D53AA*
  ID_OUI_FROM_DATABASE=RCATSONE
 
+OUI:70B3D53AB*
+ ID_OUI_FROM_DATABASE=Camozzi Automation SpA
+
 OUI:70B3D53AC*
  ID_OUI_FROM_DATABASE=RF-Tuote Oy
 
@@ -66572,6 +67265,9 @@ OUI:70B3D53C6*
 OUI:70B3D53C7*
  ID_OUI_FROM_DATABASE=SOFTCREATE CORP.
 
+OUI:70B3D53C8*
+ ID_OUI_FROM_DATABASE=ABC Electric Co.
+
 OUI:70B3D53C9*
  ID_OUI_FROM_DATABASE=Duerkopp-Adler
 
@@ -66596,6 +67292,9 @@ OUI:70B3D53CF*
 OUI:70B3D53D0*
  ID_OUI_FROM_DATABASE=ORtek Technology, Inc.
 
+OUI:70B3D53D1*
+ ID_OUI_FROM_DATABASE=Imenco Ltd
+
 OUI:70B3D53D2*
  ID_OUI_FROM_DATABASE=Imagine Inc.
 
@@ -66677,6 +67376,9 @@ OUI:70B3D53EC*
 OUI:70B3D53ED*
  ID_OUI_FROM_DATABASE=Ultra Electronics Sonar System Division
 
+OUI:70B3D53EE*
+ ID_OUI_FROM_DATABASE=Laser Imagineering Vertriebs GmbH
+
 OUI:70B3D53EF*
  ID_OUI_FROM_DATABASE=Vtron Pty Ltd
 
@@ -66764,6 +67466,9 @@ OUI:70B3D540A*
 OUI:70B3D540B*
  ID_OUI_FROM_DATABASE=QUERCUS TECHNOLOGIES, S.L.
 
+OUI:70B3D540C*
+ ID_OUI_FROM_DATABASE=Tornado Modular Systems
+
 OUI:70B3D540D*
  ID_OUI_FROM_DATABASE=Grupo Epelsa S.L.
 
@@ -66821,6 +67526,9 @@ OUI:70B3D5421*
 OUI:70B3D5422*
  ID_OUI_FROM_DATABASE=SUS Corporation
 
+OUI:70B3D5423*
+ ID_OUI_FROM_DATABASE=Harman Connected Services Corporation India Pvt. Ltd.
+
 OUI:70B3D5424*
  ID_OUI_FROM_DATABASE=Underground Systems, Inc.
 
@@ -66941,6 +67649,12 @@ OUI:70B3D544D*
 OUI:70B3D544E*
  ID_OUI_FROM_DATABASE=Solace Systems Inc.
 
+OUI:70B3D544F*
+ ID_OUI_FROM_DATABASE=Velvac Incorporated
+
+OUI:70B3D5453*
+ ID_OUI_FROM_DATABASE=Foerster-Technik GmbH
+
 OUI:70B3D5454*
  ID_OUI_FROM_DATABASE=Golding Audio Ltd
 
@@ -67055,6 +67769,9 @@ OUI:70B3D547B*
 OUI:70B3D547C*
  ID_OUI_FROM_DATABASE=Par-Tech, Inc.
 
+OUI:70B3D547D*
+ ID_OUI_FROM_DATABASE=Shenyang TECHE Technology Co.,Ltd
+
 OUI:70B3D547E*
  ID_OUI_FROM_DATABASE=Fiber Optika Technologies Pvt. Ltd.
 
@@ -67070,9 +67787,15 @@ OUI:70B3D5481*
 OUI:70B3D5482*
  ID_OUI_FROM_DATABASE=Aeryon Labs Inc
 
+OUI:70B3D5483*
+ ID_OUI_FROM_DATABASE=LITUM BILGI TEKNOLOJILERI SAN. VE TIC. A.S.
+
 OUI:70B3D5484*
  ID_OUI_FROM_DATABASE=Hermann Sewerin GmbH
 
+OUI:70B3D5485*
+ ID_OUI_FROM_DATABASE=CLARESYS LIMITED
+
 OUI:70B3D5486*
  ID_OUI_FROM_DATABASE=ChongQing JianTao Technology Co., Ltd.
 
@@ -67136,6 +67859,9 @@ OUI:70B3D549A*
 OUI:70B3D549B*
  ID_OUI_FROM_DATABASE=Algodue Elettronica Srl
 
+OUI:70B3D549C*
+ ID_OUI_FROM_DATABASE=AC Power Corp.
+
 OUI:70B3D549D*
  ID_OUI_FROM_DATABASE=Shenzhen Chanslink Network Technology Co., Ltd
 
@@ -67250,6 +67976,9 @@ OUI:70B3D54C1*
 OUI:70B3D54C2*
  ID_OUI_FROM_DATABASE=hera Laborsysteme GmbH
 
+OUI:70B3D54C3*
+ ID_OUI_FROM_DATABASE=EA Elektroautomatik GmbH & Co. KG
+
 OUI:70B3D54C4*
  ID_OUI_FROM_DATABASE=OOO Research and Production Center Computer Technologies
 
@@ -67301,6 +68030,9 @@ OUI:70B3D54D5*
 OUI:70B3D54D6*
  ID_OUI_FROM_DATABASE=Operational Technology Solutions
 
+OUI:70B3D54D7*
+ ID_OUI_FROM_DATABASE=Technological Ray GmbH
+
 OUI:70B3D54D8*
  ID_OUI_FROM_DATABASE=Versilis Inc.
 
@@ -67325,6 +68057,9 @@ OUI:70B3D54E0*
 OUI:70B3D54E1*
  ID_OUI_FROM_DATABASE=Grupo Epelsa S.L.
 
+OUI:70B3D54E2*
+ ID_OUI_FROM_DATABASE=Transit Solutions, LLC.
+
 OUI:70B3D54E3*
  ID_OUI_FROM_DATABASE=adnexo GmbH
 
@@ -67631,6 +68366,9 @@ OUI:70B3D5550*
 OUI:70B3D5551*
  ID_OUI_FROM_DATABASE=infrachip
 
+OUI:70B3D5552*
+ ID_OUI_FROM_DATABASE=ALTIT.CO.,Ltd.
+
 OUI:70B3D5553*
  ID_OUI_FROM_DATABASE=TAALEX Systemtechnik GmbH
 
@@ -67670,6 +68408,12 @@ OUI:70B3D555E*
 OUI:70B3D555F*
  ID_OUI_FROM_DATABASE=Deep BV
 
+OUI:70B3D5561*
+ ID_OUI_FROM_DATABASE=Liberator Pty Ltd
+
+OUI:70B3D5562*
+ ID_OUI_FROM_DATABASE=JD Squared, Inc.
+
 OUI:70B3D5563*
  ID_OUI_FROM_DATABASE=Zhejiang Hao Teng Electronic Technology Co., Ltd.
 
@@ -67718,6 +68462,9 @@ OUI:70B3D5571*
 OUI:70B3D5572*
  ID_OUI_FROM_DATABASE=CRDE
 
+OUI:70B3D5573*
+ ID_OUI_FROM_DATABASE=GEGA ELECTRONIQUE
+
 OUI:70B3D5574*
  ID_OUI_FROM_DATABASE=Cloud Intelligence Pty Ltd
 
@@ -67781,6 +68528,9 @@ OUI:70B3D5589*
 OUI:70B3D558A*
  ID_OUI_FROM_DATABASE=ITK Dr. Kassen GmbH
 
+OUI:70B3D558B*
+ ID_OUI_FROM_DATABASE=Williams Sound LLC
+
 OUI:70B3D558C*
  ID_OUI_FROM_DATABASE=OPTSYS
 
@@ -67976,6 +68726,9 @@ OUI:70B3D55D5*
 OUI:70B3D55D6*
  ID_OUI_FROM_DATABASE=BMT Messtechnik Gmbh
 
+OUI:70B3D55D7*
+ ID_OUI_FROM_DATABASE=Clockwork Dog
+
 OUI:70B3D55D8*
  ID_OUI_FROM_DATABASE=LYNX Technik AG
 
@@ -68063,6 +68816,9 @@ OUI:70B3D55F3*
 OUI:70B3D55F4*
  ID_OUI_FROM_DATABASE=FDSTiming
 
+OUI:70B3D55F5*
+ ID_OUI_FROM_DATABASE=Microvision
+
 OUI:70B3D55F6*
  ID_OUI_FROM_DATABASE=FreeFlight Systems
 
@@ -68165,6 +68921,9 @@ OUI:70B3D5617*
 OUI:70B3D5618*
  ID_OUI_FROM_DATABASE=Motec Pty Ltd
 
+OUI:70B3D5619*
+ ID_OUI_FROM_DATABASE=ZAO ZEO
+
 OUI:70B3D561A*
  ID_OUI_FROM_DATABASE=Rocket Lab Ltd.
 
@@ -68186,9 +68945,18 @@ OUI:70B3D561F*
 OUI:70B3D5620*
  ID_OUI_FROM_DATABASE=Orlaco Products B.V.
 
+OUI:70B3D5621*
+ ID_OUI_FROM_DATABASE=SERTEC SRL
+
+OUI:70B3D5622*
+ ID_OUI_FROM_DATABASE=PCS Inc.
+
 OUI:70B3D5623*
  ID_OUI_FROM_DATABASE=Beijing HuaLian Technology Co, Ltd.
 
+OUI:70B3D5624*
+ ID_OUI_FROM_DATABASE=EBE Mobility & Green Energy GmbH
+
 OUI:70B3D5625*
  ID_OUI_FROM_DATABASE=VX Instruments GmbH
 
@@ -68282,6 +69050,9 @@ OUI:70B3D5644*
 OUI:70B3D5645*
  ID_OUI_FROM_DATABASE=Project Decibel, Inc.
 
+OUI:70B3D5646*
+ ID_OUI_FROM_DATABASE=Xirgo Technologies LLC
+
 OUI:70B3D5647*
  ID_OUI_FROM_DATABASE=KZTA
 
@@ -68363,6 +69134,9 @@ OUI:70B3D5661*
 OUI:70B3D5662*
  ID_OUI_FROM_DATABASE=Icon Industrial Engineering
 
+OUI:70B3D5663*
+ ID_OUI_FROM_DATABASE=Intrinsic Group Limited
+
 OUI:70B3D5664*
  ID_OUI_FROM_DATABASE=Sankyo Intec co.,ltd
 
@@ -68375,6 +69149,9 @@ OUI:70B3D5666*
 OUI:70B3D5667*
  ID_OUI_FROM_DATABASE=CT Company
 
+OUI:70B3D5668*
+ ID_OUI_FROM_DATABASE=Öresundskraft AB
+
 OUI:70B3D5669*
  ID_OUI_FROM_DATABASE=Panoramic Power
 
@@ -68627,6 +69404,9 @@ OUI:70B3D56C2*
 OUI:70B3D56C3*
  ID_OUI_FROM_DATABASE=BEIJING ZGH SECURITY RESEARCH INSTITUTE CO., LTD
 
+OUI:70B3D56C4*
+ ID_OUI_FROM_DATABASE=Veo Robotics, Inc.
+
 OUI:70B3D56C5*
  ID_OUI_FROM_DATABASE=CJSC «Russian telecom equipment company» (CJSC RTEC)
 
@@ -68636,6 +69416,9 @@ OUI:70B3D56C6*
 OUI:70B3D56C7*
  ID_OUI_FROM_DATABASE=Becton Dickinson
 
+OUI:70B3D56C8*
+ ID_OUI_FROM_DATABASE=Sicon srl
+
 OUI:70B3D56C9*
  ID_OUI_FROM_DATABASE=Redstone Sunshine(Beijing)Technology Co.,Ltd.
 
@@ -68702,6 +69485,9 @@ OUI:70B3D56E0*
 OUI:70B3D56E1*
  ID_OUI_FROM_DATABASE=Shanghai Holystar Information Technology Co.,Ltd
 
+OUI:70B3D56E2*
+ ID_OUI_FROM_DATABASE=E-Controls
+
 OUI:70B3D56E3*
  ID_OUI_FROM_DATABASE=SHEN ZHEN QLS ELECTRONIC TECHNOLOGY CO.,LTD.
 
@@ -68738,6 +69524,9 @@ OUI:70B3D56ED*
 OUI:70B3D56EE*
  ID_OUI_FROM_DATABASE=HANKOOK CTEC CO,. LTD.
 
+OUI:70B3D56EF*
+ ID_OUI_FROM_DATABASE=Beringar
+
 OUI:70B3D56F0*
  ID_OUI_FROM_DATABASE=iTelaSoft Pvt Ltd
 
@@ -68864,6 +69653,9 @@ OUI:70B3D571B*
 OUI:70B3D571C*
  ID_OUI_FROM_DATABASE=Konzept Informationssysteme GmbH
 
+OUI:70B3D571D*
+ ID_OUI_FROM_DATABASE=Connido Limited
+
 OUI:70B3D571E*
  ID_OUI_FROM_DATABASE=Motec Pty Ltd
 
@@ -68934,7 +69726,7 @@ OUI:70B3D5737*
  ID_OUI_FROM_DATABASE=SD Biosensor
 
 OUI:70B3D5738*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=GRYPHON SECURE INC
 
 OUI:70B3D5739*
  ID_OUI_FROM_DATABASE=Zigencorp, Inc
@@ -69221,6 +70013,9 @@ OUI:70B3D579A*
 OUI:70B3D579B*
  ID_OUI_FROM_DATABASE=Soniclean Pty Ltd
 
+OUI:70B3D579C*
+ ID_OUI_FROM_DATABASE=ADDE
+
 OUI:70B3D579D*
  ID_OUI_FROM_DATABASE=Editech Co., Ltd
 
@@ -69281,6 +70076,9 @@ OUI:70B3D57AF*
 OUI:70B3D57B0*
  ID_OUI_FROM_DATABASE=Medisafe International
 
+OUI:70B3D57B1*
+ ID_OUI_FROM_DATABASE=Panamera
+
 OUI:70B3D57B2*
  ID_OUI_FROM_DATABASE=Rail Power Systems GmbH
 
@@ -69290,6 +70088,9 @@ OUI:70B3D57B3*
 OUI:70B3D57B4*
  ID_OUI_FROM_DATABASE=Zumbach Electronic AG
 
+OUI:70B3D57B5*
+ ID_OUI_FROM_DATABASE=VOCAL Technologies Ltd.
+
 OUI:70B3D57B6*
  ID_OUI_FROM_DATABASE=Amada Miyachi America Inc.
 
@@ -69311,6 +70112,9 @@ OUI:70B3D57BB*
 OUI:70B3D57BC*
  ID_OUI_FROM_DATABASE=FIRST RF Corporation
 
+OUI:70B3D57BD*
+ ID_OUI_FROM_DATABASE=TableConnect GmbH
+
 OUI:70B3D57BE*
  ID_OUI_FROM_DATABASE=Phytron GmbH
 
@@ -69386,6 +70190,9 @@ OUI:70B3D57D6*
 OUI:70B3D57D7*
  ID_OUI_FROM_DATABASE=Gedomo GmbH
 
+OUI:70B3D57D8*
+ ID_OUI_FROM_DATABASE=Nuand LLC
+
 OUI:70B3D57D9*
  ID_OUI_FROM_DATABASE=ATOM GIKEN Co.,Ltd.
 
@@ -69441,7 +70248,7 @@ OUI:70B3D57EB*
  ID_OUI_FROM_DATABASE=Xerox International Partners
 
 OUI:70B3D57EC*
- ID_OUI_FROM_DATABASE=GRIDSMART Technologies
+ ID_OUI_FROM_DATABASE=Cubic ITS, Inc. dba GRIDSMART Technologies
 
 OUI:70B3D57ED*
  ID_OUI_FROM_DATABASE=The Things Network Foundation
@@ -69453,7 +70260,7 @@ OUI:70B3D57EF*
  ID_OUI_FROM_DATABASE=CRAVIS CO., LIMITED
 
 OUI:70B3D57F0*
- ID_OUI_FROM_DATABASE=Yokogawa Denshikiki Co.,Ltd
+ ID_OUI_FROM_DATABASE=YDK Technologies Co.,Ltd
 
 OUI:70B3D57F1*
  ID_OUI_FROM_DATABASE=AeroVision Avionics, Inc.
@@ -69512,6 +70319,9 @@ OUI:70B3D5804*
 OUI:70B3D5805*
  ID_OUI_FROM_DATABASE=Eurotronik Kranj d.o.o.
 
+OUI:70B3D5806*
+ ID_OUI_FROM_DATABASE=International Super Computer Co., Ltd.
+
 OUI:70B3D5807*
  ID_OUI_FROM_DATABASE=Camsat Przemysław Gralak
 
@@ -69656,6 +70466,9 @@ OUI:70B3D583B*
 OUI:70B3D583C*
  ID_OUI_FROM_DATABASE=Sinoembed
 
+OUI:70B3D583D*
+ ID_OUI_FROM_DATABASE=Gentec
+
 OUI:70B3D583E*
  ID_OUI_FROM_DATABASE=The Dini Group, La Jolla inc.
 
@@ -69737,6 +70550,9 @@ OUI:70B3D5857*
 OUI:70B3D5858*
  ID_OUI_FROM_DATABASE=Hubbell Power Systems
 
+OUI:70B3D5859*
+ ID_OUI_FROM_DATABASE=HAN CHANG
+
 OUI:70B3D585A*
  ID_OUI_FROM_DATABASE=BRUSHIES
 
@@ -69860,6 +70676,9 @@ OUI:70B3D5881*
 OUI:70B3D5882*
  ID_OUI_FROM_DATABASE=SIMON TECH, S.L.
 
+OUI:70B3D5883*
+ ID_OUI_FROM_DATABASE=Contec Americas Inc.
+
 OUI:70B3D5884*
  ID_OUI_FROM_DATABASE=LG Electronics
 
@@ -70001,6 +70820,12 @@ OUI:70B3D58B3*
 OUI:70B3D58B4*
  ID_OUI_FROM_DATABASE=Scenario Automation
 
+OUI:70B3D58B5*
+ ID_OUI_FROM_DATABASE=xTom GmbH
+
+OUI:70B3D58B6*
+ ID_OUI_FROM_DATABASE=Eldes Ltd
+
 OUI:70B3D58B7*
  ID_OUI_FROM_DATABASE=Contec Americas Inc.
 
@@ -70079,6 +70904,9 @@ OUI:70B3D58D0*
 OUI:70B3D58D3*
  ID_OUI_FROM_DATABASE=PERFORMANCE CONTROLS, INC.
 
+OUI:70B3D58D4*
+ ID_OUI_FROM_DATABASE=Guangdong Transtek Medical Electronics Co., Ltd.
+
 OUI:70B3D58D5*
  ID_OUI_FROM_DATABASE=Guangzhou Wanglu
 
@@ -70175,9 +71003,15 @@ OUI:70B3D58F7*
 OUI:70B3D58F8*
  ID_OUI_FROM_DATABASE=Wi6labs
 
+OUI:70B3D58F9*
+ ID_OUI_FROM_DATABASE=IWS Global Pty Ltd
+
 OUI:70B3D58FA*
  ID_OUI_FROM_DATABASE=DEA SYSTEM SPA
 
+OUI:70B3D58FB*
+ ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme
+
 OUI:70B3D58FC*
  ID_OUI_FROM_DATABASE=Mianjie Technology
 
@@ -70211,6 +71045,9 @@ OUI:70B3D5907*
 OUI:70B3D5908*
  ID_OUI_FROM_DATABASE=Accusonic
 
+OUI:70B3D5909*
+ ID_OUI_FROM_DATABASE=tetronik GmbH AEN
+
 OUI:70B3D590A*
  ID_OUI_FROM_DATABASE=Hangzhou SunTown Intelligent Science & Technology Co.,Ltd.
 
@@ -70271,6 +71108,9 @@ OUI:70B3D591F*
 OUI:70B3D5920*
  ID_OUI_FROM_DATABASE=SLAT
 
+OUI:70B3D5921*
+ ID_OUI_FROM_DATABASE=QDevil
+
 OUI:70B3D5922*
  ID_OUI_FROM_DATABASE=Adcole Space
 
@@ -70346,6 +71186,9 @@ OUI:70B3D593A*
 OUI:70B3D593B*
  ID_OUI_FROM_DATABASE=Changchun FAW Yanfeng Visteon Automotive Electronics.,Ltd.
 
+OUI:70B3D593D*
+ ID_OUI_FROM_DATABASE=Elmeasure India Pvt Ltd
+
 OUI:70B3D593E*
  ID_OUI_FROM_DATABASE=Systems With Intelligence Inc.
 
@@ -70454,6 +71297,9 @@ OUI:70B3D5960*
 OUI:70B3D5961*
  ID_OUI_FROM_DATABASE=TASK SISTEMAS DE COMPUTACAO LTDA
 
+OUI:70B3D5962*
+ ID_OUI_FROM_DATABASE=Senquire Pte. Ltd
+
 OUI:70B3D5963*
  ID_OUI_FROM_DATABASE=Triax A/S
 
@@ -70556,6 +71402,9 @@ OUI:70B3D5986*
 OUI:70B3D5987*
  ID_OUI_FROM_DATABASE=AXIS CORPORATION
 
+OUI:70B3D5988*
+ ID_OUI_FROM_DATABASE=Arris
+
 OUI:70B3D5989*
  ID_OUI_FROM_DATABASE=DCNS
 
@@ -70628,12 +71477,18 @@ OUI:70B3D59A1*
 OUI:70B3D59A2*
  ID_OUI_FROM_DATABASE=O-Net Communications(Shenzhen)Limited
 
+OUI:70B3D59A3*
+ ID_OUI_FROM_DATABASE=Shanghai Hourui Technology Co., Ltd.
+
 OUI:70B3D59A4*
  ID_OUI_FROM_DATABASE=Nordmann International GmbH
 
 OUI:70B3D59A5*
  ID_OUI_FROM_DATABASE=Softel
 
+OUI:70B3D59A6*
+ ID_OUI_FROM_DATABASE=QUNU LABS PRIVATE LIMITED
+
 OUI:70B3D59A7*
  ID_OUI_FROM_DATABASE=Honeywell
 
@@ -70694,6 +71549,9 @@ OUI:70B3D59B9*
 OUI:70B3D59BA*
  ID_OUI_FROM_DATABASE=ATIM Radiocommunication
 
+OUI:70B3D59BB*
+ ID_OUI_FROM_DATABASE=Jinga-hi, Inc.
+
 OUI:70B3D59BD*
  ID_OUI_FROM_DATABASE=Signal Processing Devices Sweden AB
 
@@ -70896,7 +71754,7 @@ OUI:70B3D5A01*
  ID_OUI_FROM_DATABASE=FeldTech GmbH
 
 OUI:70B3D5A03*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Proemion GmbH
 
 OUI:70B3D5A04*
  ID_OUI_FROM_DATABASE=Galea Electric S.L.
@@ -71018,6 +71876,9 @@ OUI:70B3D5A2F*
 OUI:70B3D5A30*
  ID_OUI_FROM_DATABASE=SHEN ZHEN HUAWANG TECHNOLOGY CO; LTD
 
+OUI:70B3D5A31*
+ ID_OUI_FROM_DATABASE=Private
+
 OUI:70B3D5A32*
  ID_OUI_FROM_DATABASE=Toughdog Security Systems
 
@@ -71054,6 +71915,9 @@ OUI:70B3D5A3C*
 OUI:70B3D5A3D*
  ID_OUI_FROM_DATABASE=SMART IN OVATION GmbH
 
+OUI:70B3D5A3E*
+ ID_OUI_FROM_DATABASE=Vigorcloud Co., Ltd.
+
 OUI:70B3D5A3F*
  ID_OUI_FROM_DATABASE=PHPower Srl
 
@@ -71156,6 +72020,9 @@ OUI:70B3D5A5F*
 OUI:70B3D5A60*
  ID_OUI_FROM_DATABASE=Pneumax S.p.A.
 
+OUI:70B3D5A61*
+ ID_OUI_FROM_DATABASE=Omsk Manufacturing Association named after A.S. Popov
+
 OUI:70B3D5A62*
  ID_OUI_FROM_DATABASE=Environexus
 
@@ -71381,6 +72248,9 @@ OUI:70B3D5AAF*
 OUI:70B3D5AB0*
  ID_OUI_FROM_DATABASE=OSR R&D ISRAEL LTD
 
+OUI:70B3D5AB1*
+ ID_OUI_FROM_DATABASE=ISRV Zrt.
+
 OUI:70B3D5AB2*
  ID_OUI_FROM_DATABASE=Power Electronics Espana, S.L.
 
@@ -71630,6 +72500,9 @@ OUI:70B3D5B0B*
 OUI:70B3D5B0C*
  ID_OUI_FROM_DATABASE=Vigilate srl
 
+OUI:70B3D5B0E*
+ ID_OUI_FROM_DATABASE=Servotronix Motion Control
+
 OUI:70B3D5B0F*
  ID_OUI_FROM_DATABASE=merkur Funksysteme AG
 
@@ -71642,6 +72515,9 @@ OUI:70B3D5B11*
 OUI:70B3D5B13*
  ID_OUI_FROM_DATABASE=Omwave
 
+OUI:70B3D5B14*
+ ID_OUI_FROM_DATABASE=Pantherun Technologies Pvt Ltd
+
 OUI:70B3D5B15*
  ID_OUI_FROM_DATABASE=Eta Beta Srl
 
@@ -71663,6 +72539,9 @@ OUI:70B3D5B1A*
 OUI:70B3D5B1B*
  ID_OUI_FROM_DATABASE=Technology Link Corporation
 
+OUI:70B3D5B1C*
+ ID_OUI_FROM_DATABASE=Serveron / Qualitrol
+
 OUI:70B3D5B1D*
  ID_OUI_FROM_DATABASE=Safelet BV
 
@@ -71678,6 +72557,9 @@ OUI:70B3D5B20*
 OUI:70B3D5B21*
  ID_OUI_FROM_DATABASE=TATTILE SRL
 
+OUI:70B3D5B22*
+ ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
+
 OUI:70B3D5B23*
  ID_OUI_FROM_DATABASE=Supervision Test et Pilotage
 
@@ -71768,6 +72650,9 @@ OUI:70B3D5B43*
 OUI:70B3D5B44*
  ID_OUI_FROM_DATABASE=ENTEC Electric & Electronic Co., LTD.
 
+OUI:70B3D5B45*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision IND.CO.,LTD
+
 OUI:70B3D5B46*
  ID_OUI_FROM_DATABASE=FAS Electronics (Fujian) Co.,LTD.
 
@@ -71840,6 +72725,9 @@ OUI:70B3D5B5F*
 OUI:70B3D5B60*
  ID_OUI_FROM_DATABASE=ZAO ZEO
 
+OUI:70B3D5B61*
+ ID_OUI_FROM_DATABASE=WuXi anktech Co., Ltd
+
 OUI:70B3D5B62*
  ID_OUI_FROM_DATABASE=Sakura Seiki Co.,Ltd.
 
@@ -71861,6 +72749,9 @@ OUI:70B3D5B67*
 OUI:70B3D5B68*
  ID_OUI_FROM_DATABASE=S-Rain Control A/S
 
+OUI:70B3D5B69*
+ ID_OUI_FROM_DATABASE=Daatrics LTD
+
 OUI:70B3D5B6A*
  ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
 
@@ -71880,7 +72771,7 @@ OUI:70B3D5B6F*
  ID_OUI_FROM_DATABASE=Integra Metering SAS
 
 OUI:70B3D5B71*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Optiver Pty Ltd
 
 OUI:70B3D5B72*
  ID_OUI_FROM_DATABASE=UB330.net d.o.o.
@@ -71930,6 +72821,9 @@ OUI:70B3D5B81*
 OUI:70B3D5B82*
  ID_OUI_FROM_DATABASE=Lookout Portable Security
 
+OUI:70B3D5B83*
+ ID_OUI_FROM_DATABASE=Matrix Telematics Limited
+
 OUI:70B3D5B84*
  ID_OUI_FROM_DATABASE=OOO Research and Production Center Computer Technologies
 
@@ -71937,7 +72831,7 @@ OUI:70B3D5B85*
  ID_OUI_FROM_DATABASE=Fenotech Inc.
 
 OUI:70B3D5B86*
- ID_OUI_FROM_DATABASE=Cubitech
+ ID_OUI_FROM_DATABASE=Hilo
 
 OUI:70B3D5B87*
  ID_OUI_FROM_DATABASE=CAITRON GmbH
@@ -72089,6 +72983,9 @@ OUI:70B3D5BBA*
 OUI:70B3D5BBB*
  ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
 
+OUI:70B3D5BBC*
+ ID_OUI_FROM_DATABASE=Boundary Technologies Ltd
+
 OUI:70B3D5BBD*
  ID_OUI_FROM_DATABASE=Providius Corp
 
@@ -72176,6 +73073,9 @@ OUI:70B3D5BDA*
 OUI:70B3D5BDD*
  ID_OUI_FROM_DATABASE=CDR SRL
 
+OUI:70B3D5BDE*
+ ID_OUI_FROM_DATABASE=CAST Group of Companies Inc.
+
 OUI:70B3D5BDF*
  ID_OUI_FROM_DATABASE=H2O-YUG LLC
 
@@ -72185,6 +73085,9 @@ OUI:70B3D5BE0*
 OUI:70B3D5BE1*
  ID_OUI_FROM_DATABASE=FeCon GmbH
 
+OUI:70B3D5BE2*
+ ID_OUI_FROM_DATABASE=Nocix, LLC
+
 OUI:70B3D5BE3*
  ID_OUI_FROM_DATABASE=Saratov Electrounit Production Plant named after Sergo Ordzhonikidze, OJSC
 
@@ -72209,6 +73112,9 @@ OUI:70B3D5BE9*
 OUI:70B3D5BEA*
  ID_OUI_FROM_DATABASE=Virtuosys Ltd
 
+OUI:70B3D5BEB*
+ ID_OUI_FROM_DATABASE=Potter Electric Signal Co. LLC
+
 OUI:70B3D5BEC*
  ID_OUI_FROM_DATABASE=Tokyo Communication Equipment MFG Co.,ltd.
 
@@ -72230,6 +73136,9 @@ OUI:70B3D5BF2*
 OUI:70B3D5BF3*
  ID_OUI_FROM_DATABASE=CG-WIRELESS
 
+OUI:70B3D5BF4*
+ ID_OUI_FROM_DATABASE=CreevX
+
 OUI:70B3D5BF5*
  ID_OUI_FROM_DATABASE=Acacia Research
 
@@ -72458,6 +73367,9 @@ OUI:70B3D5C44*
 OUI:70B3D5C45*
  ID_OUI_FROM_DATABASE=Stiebel Eltron GmbH
 
+OUI:70B3D5C46*
+ ID_OUI_FROM_DATABASE=eumig industrie-TV GmbH.
+
 OUI:70B3D5C48*
  ID_OUI_FROM_DATABASE=Weltek Technologies Co. Ltd.
 
@@ -72503,6 +73415,9 @@ OUI:70B3D5C55*
 OUI:70B3D5C56*
  ID_OUI_FROM_DATABASE=TELETASK
 
+OUI:70B3D5C57*
+ ID_OUI_FROM_DATABASE=eBZ GmbH
+
 OUI:70B3D5C58*
  ID_OUI_FROM_DATABASE=RMI Laser LLC
 
@@ -72794,6 +73709,9 @@ OUI:70B3D5CBD*
 OUI:70B3D5CBE*
  ID_OUI_FROM_DATABASE=Ensura Solutions BV
 
+OUI:70B3D5CBF*
+ ID_OUI_FROM_DATABASE=Cubic ITS, Inc. dba GRIDSMART Technologies
+
 OUI:70B3D5CC1*
  ID_OUI_FROM_DATABASE=BEEcube Inc.
 
@@ -72872,6 +73790,9 @@ OUI:70B3D5CDB*
 OUI:70B3D5CDC*
  ID_OUI_FROM_DATABASE=Dat-Con d.o.o.
 
+OUI:70B3D5CDD*
+ ID_OUI_FROM_DATABASE=Teneo IoT B.V.
+
 OUI:70B3D5CDE*
  ID_OUI_FROM_DATABASE=Multipure International
 
@@ -72902,6 +73823,9 @@ OUI:70B3D5CE9*
 OUI:70B3D5CEA*
  ID_OUI_FROM_DATABASE=Computerwise, Inc.
 
+OUI:70B3D5CEC*
+ ID_OUI_FROM_DATABASE=Deltronic Security AB
+
 OUI:70B3D5CED*
  ID_OUI_FROM_DATABASE=Advanced Products Corporation Pte Ltd
 
@@ -73007,6 +73931,9 @@ OUI:70B3D5D15*
 OUI:70B3D5D16*
  ID_OUI_FROM_DATABASE=Monnit Corporation
 
+OUI:70B3D5D17*
+ ID_OUI_FROM_DATABASE=Power Element
+
 OUI:70B3D5D18*
  ID_OUI_FROM_DATABASE=MetCom Solutions GmbH
 
@@ -73161,7 +74088,7 @@ OUI:70B3D5D4F*
  ID_OUI_FROM_DATABASE=C-COM Satellite Systems Inc.
 
 OUI:70B3D5D50*
- ID_OUI_FROM_DATABASE=GRIDSMART Technologies
+ ID_OUI_FROM_DATABASE=Cubic ITS, Inc. dba GRIDSMART Technologies
 
 OUI:70B3D5D51*
  ID_OUI_FROM_DATABASE=Azcom Technology S.r.l.
@@ -73196,6 +74123,9 @@ OUI:70B3D5D5B*
 OUI:70B3D5D5C*
  ID_OUI_FROM_DATABASE=Critical Link LLC
 
+OUI:70B3D5D5E*
+ ID_OUI_FROM_DATABASE=Barcelona Smart Technologies
+
 OUI:70B3D5D5F*
  ID_OUI_FROM_DATABASE=Core Balance Co., Ltd.
 
@@ -73295,9 +74225,15 @@ OUI:70B3D5D80*
 OUI:70B3D5D81*
  ID_OUI_FROM_DATABASE=PDD Group Ltd
 
+OUI:70B3D5D82*
+ ID_OUI_FROM_DATABASE=SUN ELECTRONICS CO.,LTD.
+
 OUI:70B3D5D84*
  ID_OUI_FROM_DATABASE=Sentry360
 
+OUI:70B3D5D85*
+ ID_OUI_FROM_DATABASE=BTG Instruments AB
+
 OUI:70B3D5D86*
  ID_OUI_FROM_DATABASE=WPGSYS Pte Ltd
 
@@ -73487,6 +74423,9 @@ OUI:70B3D5DC5*
 OUI:70B3D5DC6*
  ID_OUI_FROM_DATABASE=IDEM INC.
 
+OUI:70B3D5DC7*
+ ID_OUI_FROM_DATABASE=NUBURU Inc.
+
 OUI:70B3D5DC8*
  ID_OUI_FROM_DATABASE=Enertex Bayern GmbH
 
@@ -73500,7 +74439,7 @@ OUI:70B3D5DCC*
  ID_OUI_FROM_DATABASE=Eutron SPA
 
 OUI:70B3D5DCD*
- ID_OUI_FROM_DATABASE=C Tech Bilişim Teknolojileri San. ve Tic. AŞ
+ ID_OUI_FROM_DATABASE=C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.
 
 OUI:70B3D5DCE*
  ID_OUI_FROM_DATABASE=Stahl GmbH
@@ -73544,6 +74483,9 @@ OUI:70B3D5DDC*
 OUI:70B3D5DDD*
  ID_OUI_FROM_DATABASE=BIO RAD LABORATORIES
 
+OUI:70B3D5DDE*
+ ID_OUI_FROM_DATABASE=Abbott Diagnostics Technologies AS
+
 OUI:70B3D5DDF*
  ID_OUI_FROM_DATABASE=AeroVision Avionics, Inc.
 
@@ -73575,7 +74517,7 @@ OUI:70B3D5DE8*
  ID_OUI_FROM_DATABASE=Nation-E Ltd.
 
 OUI:70B3D5DE9*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=EkspertStroyProekt LLC
 
 OUI:70B3D5DEA*
  ID_OUI_FROM_DATABASE=Advanced Ventilation Applications, Inc.
@@ -73709,6 +74651,9 @@ OUI:70B3D5E1B*
 OUI:70B3D5E1C*
  ID_OUI_FROM_DATABASE=RoomMate AS
 
+OUI:70B3D5E1D*
+ ID_OUI_FROM_DATABASE=Galaxy Next Generation, Inc.
+
 OUI:70B3D5E1E*
  ID_OUI_FROM_DATABASE=Umano Medical Inc.
 
@@ -73722,7 +74667,7 @@ OUI:70B3D5E21*
  ID_OUI_FROM_DATABASE=LLVISION TECHNOLOGY CO.,LTD
 
 OUI:70B3D5E22*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Federated Wireless, Inc.
 
 OUI:70B3D5E23*
  ID_OUI_FROM_DATABASE=Smith Meter, Inc.
@@ -73817,6 +74762,9 @@ OUI:70B3D5E40*
 OUI:70B3D5E43*
  ID_OUI_FROM_DATABASE=SL Audio A/S
 
+OUI:70B3D5E44*
+ ID_OUI_FROM_DATABASE=BrainboxAI Inc
+
 OUI:70B3D5E45*
  ID_OUI_FROM_DATABASE=Momentum Data Systems
 
@@ -73904,9 +74852,15 @@ OUI:70B3D5E63*
 OUI:70B3D5E64*
  ID_OUI_FROM_DATABASE=HONG JIANG ELECTRONICS CO., LTD.
 
+OUI:70B3D5E65*
+ ID_OUI_FROM_DATABASE=BIRTECH TECHNOLOGY
+
 OUI:70B3D5E67*
  ID_OUI_FROM_DATABASE=APPLIED PROCESSING
 
+OUI:70B3D5E68*
+ ID_OUI_FROM_DATABASE=Transit Solutions, LLC.
+
 OUI:70B3D5E69*
  ID_OUI_FROM_DATABASE=Fire4 Systems UK Ltd
 
@@ -73994,6 +74948,9 @@ OUI:70B3D5E85*
 OUI:70B3D5E86*
  ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
 
+OUI:70B3D5E87*
+ ID_OUI_FROM_DATABASE=STACKFORCE GmbH
+
 OUI:70B3D5E88*
  ID_OUI_FROM_DATABASE=Breas Medical AB
 
@@ -74063,6 +75020,9 @@ OUI:70B3D5E9D*
 OUI:70B3D5E9E*
  ID_OUI_FROM_DATABASE=MSB Elektronik und Gerätebau GmbH
 
+OUI:70B3D5E9F*
+ ID_OUI_FROM_DATABASE=Gigaband IP LLC
+
 OUI:70B3D5EA0*
  ID_OUI_FROM_DATABASE=PARK24
 
@@ -74177,6 +75137,9 @@ OUI:70B3D5EC7*
 OUI:70B3D5EC8*
  ID_OUI_FROM_DATABASE=Viko Elektrik-Elektronik A.Ş.
 
+OUI:70B3D5EC9*
+ ID_OUI_FROM_DATABASE=Qlinx Technologies
+
 OUI:70B3D5ECA*
  ID_OUI_FROM_DATABASE=Transtronic AB
 
@@ -74202,11 +75165,14 @@ OUI:70B3D5ED1*
  ID_OUI_FROM_DATABASE=Przemyslowy Instytut Automatyki i Pomiarow
 
 OUI:70B3D5ED2*
- ID_OUI_FROM_DATABASE=PCTEL
+ ID_OUI_FROM_DATABASE=PCTEL, Inc.
 
 OUI:70B3D5ED3*
  ID_OUI_FROM_DATABASE=Beijing Lihong Create Co., Ltd.
 
+OUI:70B3D5ED4*
+ ID_OUI_FROM_DATABASE=WILMORE ELECTRONICS COMPANY
+
 OUI:70B3D5ED5*
  ID_OUI_FROM_DATABASE=hangzhou battle link technology Co.,Ltd
 
@@ -74504,6 +75470,9 @@ OUI:70B3D5F3E*
 OUI:70B3D5F3F*
  ID_OUI_FROM_DATABASE=comtac AG
 
+OUI:70B3D5F41*
+ ID_OUI_FROM_DATABASE=DUEVI SRL
+
 OUI:70B3D5F42*
  ID_OUI_FROM_DATABASE=Matsuhisa Corporation
 
@@ -74624,6 +75593,9 @@ OUI:70B3D5F69*
 OUI:70B3D5F6A*
  ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd.
 
+OUI:70B3D5F6B*
+ ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH
+
 OUI:70B3D5F6C*
  ID_OUI_FROM_DATABASE=VisioGreen
 
@@ -74678,6 +75650,9 @@ OUI:70B3D5F7D*
 OUI:70B3D5F7E*
  ID_OUI_FROM_DATABASE=Alpha Elettronica s.r.l.
 
+OUI:70B3D5F7F*
+ ID_OUI_FROM_DATABASE=ABL Space Systems
+
 OUI:70B3D5F80*
  ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd.
 
@@ -74726,6 +75701,9 @@ OUI:70B3D5F8E*
 OUI:70B3D5F8F*
  ID_OUI_FROM_DATABASE=DIMASTEC GESTAO DE PONTO E ACESSO EIRELI-ME
 
+OUI:70B3D5F90*
+ ID_OUI_FROM_DATABASE=Atman Tecnologia Ltda
+
 OUI:70B3D5F91*
  ID_OUI_FROM_DATABASE=Solid State Disks Ltd
 
@@ -74804,6 +75782,9 @@ OUI:70B3D5FAA*
 OUI:70B3D5FAB*
  ID_OUI_FROM_DATABASE=Open System Solutions Limited
 
+OUI:70B3D5FAC*
+ ID_OUI_FROM_DATABASE=Integrated Protein Technologies, Inc.
+
 OUI:70B3D5FAD*
  ID_OUI_FROM_DATABASE=ARC Technology Solutions, LLC
 
@@ -75674,6 +76655,9 @@ OUI:74614B*
 OUI:7463DF*
  ID_OUI_FROM_DATABASE=VTS GmbH
 
+OUI:74650C*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:7465D1*
  ID_OUI_FROM_DATABASE=Atlinks
 
@@ -75722,6 +76706,9 @@ OUI:7472B0*
 OUI:7472F2*
  ID_OUI_FROM_DATABASE=Chipsip Technology Co., Ltd.
 
+OUI:74731D*
+ ID_OUI_FROM_DATABASE=ifm electronic gmbh
+
 OUI:747336*
  ID_OUI_FROM_DATABASE=MICRODIGTAL Inc
 
@@ -75731,6 +76718,9 @@ OUI:747548*
 OUI:747818*
  ID_OUI_FROM_DATABASE=Jurumani Solutions
 
+OUI:747827*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
 OUI:747A90*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
@@ -75821,6 +76811,9 @@ OUI:748F3C*
 OUI:748F4D*
  ID_OUI_FROM_DATABASE=MEN Mikro Elektronik GmbH
 
+OUI:74901F*
+ ID_OUI_FROM_DATABASE=Ragile Networks Inc.
+
 OUI:749050*
  ID_OUI_FROM_DATABASE=Renesas Electronics Corporation
 
@@ -75837,7 +76830,7 @@ OUI:74943D*
  ID_OUI_FROM_DATABASE=AgJunction
 
 OUI:7495EC*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:749637*
  ID_OUI_FROM_DATABASE=Todaair Electronic Co., Ltd
@@ -75935,6 +76928,9 @@ OUI:74B587*
 OUI:74B6B6*
  ID_OUI_FROM_DATABASE=eero inc.
 
+OUI:74B7B3*
+ ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd
+
 OUI:74B91E*
  ID_OUI_FROM_DATABASE=Nanjing Bestway Automation System Co., Ltd
 
@@ -76022,6 +77018,9 @@ OUI:74D654*
 OUI:74D675*
  ID_OUI_FROM_DATABASE=WYMA Tecnologia
 
+OUI:74D6CB*
+ ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
+
 OUI:74D6EA*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
@@ -76166,6 +77165,9 @@ OUI:74EB80*
 OUI:74EC42*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
+OUI:74ECB2*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:74ECF1*
  ID_OUI_FROM_DATABASE=Acumen
 
@@ -76298,6 +77300,9 @@ OUI:780541*
 OUI:78055F*
  ID_OUI_FROM_DATABASE=Shenzhen WYC Technology Co., Ltd.
 
+OUI:78058C*
+ ID_OUI_FROM_DATABASE=mMax Communications, Inc.
+
 OUI:780738*
  ID_OUI_FROM_DATABASE=Z.U.K. Elzab S.A.
 
@@ -76355,6 +77360,9 @@ OUI:781DBA*
 OUI:781DFD*
  ID_OUI_FROM_DATABASE=Jabil Inc
 
+OUI:781F11*
+ ID_OUI_FROM_DATABASE=RAB Lighting
+
 OUI:781FDB*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -76406,6 +77414,9 @@ OUI:782C29*
 OUI:782D7E*
  ID_OUI_FROM_DATABASE=TRENDnet, Inc.
 
+OUI:782E56*
+ ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd.
+
 OUI:782EEF*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
@@ -76481,6 +77492,9 @@ OUI:784558*
 OUI:784561*
  ID_OUI_FROM_DATABASE=CyberTAN Technology Inc.
 
+OUI:7845B3*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:7845C4*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
@@ -76601,6 +77615,9 @@ OUI:7868F7*
 OUI:7869D4*
  ID_OUI_FROM_DATABASE=Shenyang Vibrotech Instruments Inc.
 
+OUI:786A1F*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:786A89*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -76631,6 +77648,9 @@ OUI:787D48*
 OUI:787D53*
  ID_OUI_FROM_DATABASE=Extreme Networks, Inc.
 
+OUI:787DF3*
+ ID_OUI_FROM_DATABASE=Sterlite Technologies Limited
+
 OUI:787E61*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -76694,6 +77714,9 @@ OUI:788DF7*
 OUI:788E33*
  ID_OUI_FROM_DATABASE=Jiangsu SEUIC Technology Co.,Ltd
 
+OUI:7891E9*
+ ID_OUI_FROM_DATABASE=Raisecom Technology CO.,LTD
+
 OUI:78923E*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
@@ -76706,6 +77729,9 @@ OUI:7894B4*
 OUI:7894E8*
  ID_OUI_FROM_DATABASE=Radio Bridge
 
+OUI:7895EB*
+ ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED
+
 OUI:789682*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -76715,6 +77741,9 @@ OUI:789684*
 OUI:7897C3*
  ID_OUI_FROM_DATABASE=DINGXIN INFORMATION TECHNOLOGY CO.,LTD
 
+OUI:7898E8*
+ ID_OUI_FROM_DATABASE=D-Link International
+
 OUI:7898FD*
  ID_OUI_FROM_DATABASE=Q9 Networks Inc.
 
@@ -76940,6 +77969,9 @@ OUI:78C6BB*
 OUI:78C881*
  ID_OUI_FROM_DATABASE=Sony Interactive Entertainment Inc.
 
+OUI:78C95E*
+ ID_OUI_FROM_DATABASE=Midmark RTLS
+
 OUI:78CA04*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
@@ -76994,6 +78026,9 @@ OUI:78CA83D*
 OUI:78CA83E*
  ID_OUI_FROM_DATABASE=Konecranes
 
+OUI:78CB2C*
+ ID_OUI_FROM_DATABASE=Join Digital, Inc.
+
 OUI:78CB33*
  ID_OUI_FROM_DATABASE=DHC Software Co.,Ltd
 
@@ -77165,6 +78200,9 @@ OUI:78EC74*
 OUI:78EF4C*
  ID_OUI_FROM_DATABASE=Unetconvergence Co., Ltd.
 
+OUI:78F09B*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:78F29E*
  ID_OUI_FROM_DATABASE=PEGATRON CORPORATION
 
@@ -77495,6 +78533,9 @@ OUI:7C4C58*
 OUI:7C4CA5*
  ID_OUI_FROM_DATABASE=BSkyB Ltd
 
+OUI:7C4E09*
+ ID_OUI_FROM_DATABASE=Shenzhen Skyworth Wireless Technology Co.,Ltd
+
 OUI:7C4F7D*
  ID_OUI_FROM_DATABASE=Sawwave
 
@@ -77663,6 +78704,9 @@ OUI:7C72E4*
 OUI:7C738B*
  ID_OUI_FROM_DATABASE=Cocoon Alarm Ltd
 
+OUI:7C73EB*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:7C7630*
  ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd
 
@@ -77678,6 +78722,9 @@ OUI:7C7673*
 OUI:7C787E*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:7C78B2*
+ ID_OUI_FROM_DATABASE=Wyze Labs Inc
+
 OUI:7C79E8*
  ID_OUI_FROM_DATABASE=PayRange Inc.
 
@@ -77729,6 +78776,9 @@ OUI:7C8D91*
 OUI:7C8EE4*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:7C8FDE*
+ ID_OUI_FROM_DATABASE=DWnet Technologies(Suzhou) Corporation
+
 OUI:7C9122*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -77954,6 +79004,9 @@ OUI:7CBF88*
 OUI:7CBFB1*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:7CC294*
+ ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd
+
 OUI:7CC385*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -78230,6 +79283,9 @@ OUI:80029C*
 OUI:8002DF*
  ID_OUI_FROM_DATABASE=ORA Inc.
 
+OUI:800384*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
 OUI:800588*
  ID_OUI_FROM_DATABASE=Ruijie Networks Co.,LTD
 
@@ -78578,6 +79634,9 @@ OUI:80739F*
 OUI:807459*
  ID_OUI_FROM_DATABASE=K's Co.,Ltd.
 
+OUI:807484*
+ ID_OUI_FROM_DATABASE=ALL Winner (Hong Kong) Limited
+
 OUI:80751F*
  ID_OUI_FROM_DATABASE=BSkyB Ltd
 
@@ -78707,6 +79766,9 @@ OUI:808DB7*
 OUI:808F1D*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:808FE8*
+ ID_OUI_FROM_DATABASE=Intelbras
+
 OUI:80912A*
  ID_OUI_FROM_DATABASE=Lih Rong electronic Enterprise Co., Ltd.
 
@@ -78746,6 +79808,9 @@ OUI:809F9B*
 OUI:809FAB*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
+OUI:809FF5*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:80A036*
  ID_OUI_FROM_DATABASE=Shanghai MXCHIP Information Technology Co., Ltd.
 
@@ -78860,6 +79925,9 @@ OUI:80C7C5*
 OUI:80C862*
  ID_OUI_FROM_DATABASE=Openpeak, Inc
 
+OUI:80C955*
+ ID_OUI_FROM_DATABASE=Redpine Signals, Inc.
+
 OUI:80CA4B*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LTD
 
@@ -79031,6 +80099,9 @@ OUI:80F503*
 OUI:80F593*
  ID_OUI_FROM_DATABASE=IRCO Sistemas de Telecomunicación S.A.
 
+OUI:80F5B5*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:80F62E*
  ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
 
@@ -79088,6 +80159,51 @@ OUI:84100D*
 OUI:84119E*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:8411C20*
+ ID_OUI_FROM_DATABASE=Kazdream Technologies LLP
+
+OUI:8411C21*
+ ID_OUI_FROM_DATABASE=Beijing Dayu Technology Co., Ltd.
+
+OUI:8411C22*
+ ID_OUI_FROM_DATABASE=Futurecom Systems Group
+
+OUI:8411C23*
+ ID_OUI_FROM_DATABASE=Hitachi,Ltd.
+
+OUI:8411C24*
+ ID_OUI_FROM_DATABASE=LLC STC MZTA
+
+OUI:8411C25*
+ ID_OUI_FROM_DATABASE=AIBIoT GmbH
+
+OUI:8411C26*
+ ID_OUI_FROM_DATABASE=KESSEL AG
+
+OUI:8411C27*
+ ID_OUI_FROM_DATABASE=Ei3 Corporation
+
+OUI:8411C28*
+ ID_OUI_FROM_DATABASE=Leybold GmbH
+
+OUI:8411C29*
+ ID_OUI_FROM_DATABASE=C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.
+
+OUI:8411C2A*
+ ID_OUI_FROM_DATABASE=igus GmbH
+
+OUI:8411C2B*
+ ID_OUI_FROM_DATABASE=Guangdong Creator&Flyaudio Electronic Technology Co.,LTD
+
+OUI:8411C2C*
+ ID_OUI_FROM_DATABASE=Provision-ISR
+
+OUI:8411C2D*
+ ID_OUI_FROM_DATABASE=Goldmund Switzerland
+
+OUI:8411C2E*
+ ID_OUI_FROM_DATABASE=Dangerous Music Group, LLC
+
 OUI:84139F*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -79118,6 +80234,9 @@ OUI:841B38*
 OUI:841B5E*
  ID_OUI_FROM_DATABASE=NETGEAR
 
+OUI:841B77*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:841C70*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -79196,6 +80315,9 @@ OUI:842E27*
 OUI:842F75*
  ID_OUI_FROM_DATABASE=Innokas Group
 
+OUI:843095*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision IND.CO.,LTD
+
 OUI:8430E5*
  ID_OUI_FROM_DATABASE=SkyHawke Technologies, LLC
 
@@ -79310,6 +80432,9 @@ OUI:84509A*
 OUI:845181*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:8454DF*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:8455A5*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -79334,6 +80459,9 @@ OUI:845C93*
 OUI:845DD7*
  ID_OUI_FROM_DATABASE=Shenzhen Netcom Electronics Co.,Ltd
 
+OUI:846082*
+ ID_OUI_FROM_DATABASE=Private
+
 OUI:8461A0*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -79373,6 +80501,9 @@ OUI:846EB1*
 OUI:846FCE*
  ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
 
+OUI:847127*
+ ID_OUI_FROM_DATABASE=Silicon Laboratories
+
 OUI:847207*
  ID_OUI_FROM_DATABASE=I&C Technology
 
@@ -79577,6 +80708,9 @@ OUI:849000*
 OUI:84930C*
  ID_OUI_FROM_DATABASE=InCoax Networks Europe AB
 
+OUI:8493A0*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:84948C*
  ID_OUI_FROM_DATABASE=Hitron Technologies. Inc
 
@@ -79601,6 +80735,9 @@ OUI:849CA6*
 OUI:849D64*
  ID_OUI_FROM_DATABASE=SMC Corporation
 
+OUI:849DC2*
+ ID_OUI_FROM_DATABASE=Shanghai MXCHIP Information Technology Co., Ltd.
+
 OUI:849DC5*
  ID_OUI_FROM_DATABASE=Centera Photonics Inc.
 
@@ -79751,6 +80888,9 @@ OUI:84C9B2*
 OUI:84C9C6*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT
 
+OUI:84CC63*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:84CCA8*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
@@ -79871,6 +81011,9 @@ OUI:84E323*
 OUI:84E327*
  ID_OUI_FROM_DATABASE=TAILYN TECHNOLOGIES INC
 
+OUI:84E342*
+ ID_OUI_FROM_DATABASE=Tuya?HK?Limietd
+
 OUI:84E4D9*
  ID_OUI_FROM_DATABASE=Shenzhen NEED technology Ltd.
 
@@ -79887,7 +81030,7 @@ OUI:84E892*
  ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc
 
 OUI:84EA97*
- ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor Co., Ltd.
+ ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD
 
 OUI:84EA99*
  ID_OUI_FROM_DATABASE=Vieworks
@@ -79910,6 +81053,9 @@ OUI:84EF18*
 OUI:84F129*
  ID_OUI_FROM_DATABASE=Metrascale Inc.
 
+OUI:84F147*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:84F3EB*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
@@ -79991,6 +81137,9 @@ OUI:88142B*
 OUI:881544*
  ID_OUI_FROM_DATABASE=Cisco Meraki
 
+OUI:8815C5*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:8817A3*
  ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
 
@@ -80408,6 +81557,9 @@ OUI:8887DD*
 OUI:888914*
  ID_OUI_FROM_DATABASE=All Components Incorporated
 
+OUI:88892F*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:888964*
  ID_OUI_FROM_DATABASE=GSI Electronics Inc.
 
@@ -80417,6 +81569,9 @@ OUI:888B5D*
 OUI:888C19*
  ID_OUI_FROM_DATABASE=Brady Corp Asia Pacific Ltd
 
+OUI:888E68*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:88908D*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -81068,6 +82223,9 @@ OUI:8C3330*
 OUI:8C3357*
  ID_OUI_FROM_DATABASE=HiteVision Digital Media Technology Co.,Ltd.
 
+OUI:8C3401*
+ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
+
 OUI:8C34FD*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -81113,6 +82271,51 @@ OUI:8C444F*
 OUI:8C4500*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
+OUI:8C476E0*
+ ID_OUI_FROM_DATABASE=Chipsafer Pte. Ltd.
+
+OUI:8C476E1*
+ ID_OUI_FROM_DATABASE=TelWare Corporation
+
+OUI:8C476E2*
+ ID_OUI_FROM_DATABASE=HuiZhou MIKI Communication Equipment Co.,LTD
+
+OUI:8C476E3*
+ ID_OUI_FROM_DATABASE=Shanghai Satellite Communication Technology Co.,Ltd
+
+OUI:8C476E4*
+ ID_OUI_FROM_DATABASE=Shenzhen Juding Electronics Co., Ltd.
+
+OUI:8C476E5*
+ ID_OUI_FROM_DATABASE=Square Inc.
+
+OUI:8C476E6*
+ ID_OUI_FROM_DATABASE=Oxford Nanopore Technologies Ltd.
+
+OUI:8C476E7*
+ ID_OUI_FROM_DATABASE=Private
+
+OUI:8C476E8*
+ ID_OUI_FROM_DATABASE=IntelliVIX Co. Ltd.
+
+OUI:8C476E9*
+ ID_OUI_FROM_DATABASE=Xertified AB
+
+OUI:8C476EA*
+ ID_OUI_FROM_DATABASE=AU Optronics Corporation
+
+OUI:8C476EB*
+ ID_OUI_FROM_DATABASE=Faravid Communication&Data Analysis
+
+OUI:8C476EC*
+ ID_OUI_FROM_DATABASE=Edge Networks Inc
+
+OUI:8C476ED*
+ ID_OUI_FROM_DATABASE=innolectric AG
+
+OUI:8C476EE*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
 OUI:8C47BE*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
@@ -81152,6 +82355,12 @@ OUI:8C53F7*
 OUI:8C541D*
  ID_OUI_FROM_DATABASE=LGE
 
+OUI:8C554A*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
+OUI:8C55BB*
+ ID_OUI_FROM_DATABASE=Songwoo Information & Technology Co., Ltd
+
 OUI:8C569D*
  ID_OUI_FROM_DATABASE=Imaging Solutions Group
 
@@ -81329,6 +82538,9 @@ OUI:8C7967*
 OUI:8C79F5*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:8C7A15*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
 OUI:8C7B9D*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -81476,6 +82688,12 @@ OUI:8CAAB5*
 OUI:8CAB8E*
  ID_OUI_FROM_DATABASE=Shanghai Feixun Communication Co.,Ltd.
 
+OUI:8CAE496*
+ ID_OUI_FROM_DATABASE=Chengdu BillDTE Technology Co., Ltd
+
+OUI:8CAE49A*
+ ID_OUI_FROM_DATABASE=Gigawave
+
 OUI:8CAE4C*
  ID_OUI_FROM_DATABASE=Plugable Technologies
 
@@ -81599,6 +82817,9 @@ OUI:8CCDA2*
 OUI:8CCDE8*
  ID_OUI_FROM_DATABASE=Nintendo Co., Ltd.
 
+OUI:8CCE4E*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:8CCEFD*
  ID_OUI_FROM_DATABASE=Shenzhen zhouhai technology co.,LTD
 
@@ -81728,6 +82949,9 @@ OUI:8CFCA0*
 OUI:8CFD18*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:8CFDDE*
+ ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
+
 OUI:8CFDF0*
  ID_OUI_FROM_DATABASE=Qualcomm Inc.
 
@@ -82193,6 +83417,9 @@ OUI:907EBA*
 OUI:907F61*
  ID_OUI_FROM_DATABASE=Chicony Electronics Co., Ltd.
 
+OUI:90808F*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:90812A*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -82289,6 +83516,9 @@ OUI:909864*
 OUI:909916*
  ID_OUI_FROM_DATABASE=ELVEES NeoTek OJSC
 
+OUI:909A4A*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:909A77*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
@@ -82379,6 +83609,9 @@ OUI:90B1E0*
 OUI:90B21F*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:90B4DD*
+ ID_OUI_FROM_DATABASE=Private
+
 OUI:90B686*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
@@ -82520,6 +83753,9 @@ OUI:90DB46*
 OUI:90DD5D*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:90DE80*
+ ID_OUI_FROM_DATABASE=Shenzhen Century Xinyang Technology Co., Ltd
+
 OUI:90DFB7*
  ID_OUI_FROM_DATABASE=s.m.s smart microwave sensors GmbH
 
@@ -82661,6 +83897,9 @@ OUI:90FD9F*
 OUI:90FF79*
  ID_OUI_FROM_DATABASE=Metro Ethernet Forum
 
+OUI:90FFD6*
+ ID_OUI_FROM_DATABASE=Honor Device Co., Ltd.
+
 OUI:940006*
  ID_OUI_FROM_DATABASE=jinyoung
 
@@ -82739,6 +83978,9 @@ OUI:9408C7*
 OUI:940937*
  ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
 
+OUI:9409D3*
+ ID_OUI_FROM_DATABASE=shenzhen maxtopic technology co.,ltd
+
 OUI:940B19*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -82931,6 +84173,9 @@ OUI:9454CE*
 OUI:9454DF*
  ID_OUI_FROM_DATABASE=YST CORP.
 
+OUI:945641*
+ ID_OUI_FROM_DATABASE=Palo Alto Networks
+
 OUI:9457A5*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
@@ -82946,6 +84191,9 @@ OUI:94592D*
 OUI:945B7E*
  ID_OUI_FROM_DATABASE=TRILOBIT LTDA.
 
+OUI:945F34*
+ ID_OUI_FROM_DATABASE=Renesas Electronics (Penang) Sdn. Bhd.
+
 OUI:94611E*
  ID_OUI_FROM_DATABASE=Wata Electronics Co.,Ltd.
 
@@ -82995,7 +84243,7 @@ OUI:94772B*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
 OUI:947BBE*
- ID_OUI_FROM_DATABASE=Ubicquia
+ ID_OUI_FROM_DATABASE=Ubicquia LLC
 
 OUI:947BE7*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -83123,6 +84371,9 @@ OUI:94A3CA*
 OUI:94A40C*
  ID_OUI_FROM_DATABASE=Diehl Metering GmbH
 
+OUI:94A67E*
+ ID_OUI_FROM_DATABASE=NETGEAR
+
 OUI:94A7B7*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -83153,6 +84404,9 @@ OUI:94B01F*
 OUI:94B10A*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:94B271*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:94B2CC*
  ID_OUI_FROM_DATABASE=PIONEER CORPORATION
 
@@ -83168,6 +84422,9 @@ OUI:94B86D*
 OUI:94B8C5*
  ID_OUI_FROM_DATABASE=RuggedCom Inc.
 
+OUI:94B97E*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:94B9B4*
  ID_OUI_FROM_DATABASE=Aptos Technology
 
@@ -83444,6 +84701,9 @@ OUI:94F19E*
 OUI:94F278*
  ID_OUI_FROM_DATABASE=Elma Electronic
 
+OUI:94F2BB*
+ ID_OUI_FROM_DATABASE=Valeo Vision Systems
+
 OUI:94F551*
  ID_OUI_FROM_DATABASE=Cadi Scientific Pte Ltd
 
@@ -83657,6 +84917,9 @@ OUI:980637D*
 OUI:980637E*
  ID_OUI_FROM_DATABASE=Shanghai Jinnian information technology Co. Ltd
 
+OUI:98063A*
+ ID_OUI_FROM_DATABASE=Home Control Singapore Pte Ltd
+
 OUI:98063C*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -83795,6 +85058,9 @@ OUI:983B16*
 OUI:983B8F*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:983F60*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:983F9F*
  ID_OUI_FROM_DATABASE=China SSJ (Suzhou) Network Technology Inc.
 
@@ -84071,6 +85337,9 @@ OUI:989449*
 OUI:9897D1*
  ID_OUI_FROM_DATABASE=MitraStar Technology Corp.
 
+OUI:989AB9*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:989BCB*
  ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH
 
@@ -84204,7 +85473,7 @@ OUI:98C8B8*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
 OUI:98C97C*
- ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO,LTD
+ ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD
 
 OUI:98CA33*
  ID_OUI_FROM_DATABASE=Apple, Inc.
@@ -84320,6 +85589,9 @@ OUI:98F0AB*
 OUI:98F170*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
+OUI:98F181*
+ ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
+
 OUI:98F199*
  ID_OUI_FROM_DATABASE=NEC Platforms, Ltd.
 
@@ -84533,6 +85805,9 @@ OUI:9C1D58*
 OUI:9C1E95*
  ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc
 
+OUI:9C1EA4*
+ ID_OUI_FROM_DATABASE=Renesas Electronics (Penang) Sdn. Bhd.
+
 OUI:9C1FDD*
  ID_OUI_FROM_DATABASE=Accupix Inc.
 
@@ -84551,6 +85826,9 @@ OUI:9C25BE*
 OUI:9C2840*
  ID_OUI_FROM_DATABASE=Discovery Technology,LTD..
 
+OUI:9C28B3*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:9C28BF*
  ID_OUI_FROM_DATABASE=Continental Automotive Czech Republic s.r.o.
 
@@ -84767,6 +86045,9 @@ OUI:9C5E73*
 OUI:9C5F5A*
  ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
 
+OUI:9C5FB0*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:9C611D*
  ID_OUI_FROM_DATABASE=Panasonic Corporation of North America
 
@@ -84869,6 +86150,9 @@ OUI:9C6F52*
 OUI:9C713A*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:9C7370*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:9C741A*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -84939,7 +86223,7 @@ OUI:9C8D1A*
  ID_OUI_FROM_DATABASE=INTEG process group inc
 
 OUI:9C8D7C*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:9C8DD3*
  ID_OUI_FROM_DATABASE=Leonton Technologies
@@ -84947,6 +86231,9 @@ OUI:9C8DD3*
 OUI:9C8E99*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
+OUI:9C8E9C*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:9C8ECD*
  ID_OUI_FROM_DATABASE=Amcrest Technologies
 
@@ -84980,6 +86267,9 @@ OUI:9C99A0*
 OUI:9C99CD*
  ID_OUI_FROM_DATABASE=Voippartners
 
+OUI:9C9AC0*
+ ID_OUI_FROM_DATABASE=LEGO System A/S
+
 OUI:9C9C1D*
  ID_OUI_FROM_DATABASE=Starkey Labs Inc.
 
@@ -85055,6 +86345,9 @@ OUI:9CB206*
 OUI:9CB2B2*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:9CB2E8*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:9CB654*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
@@ -85772,6 +87065,9 @@ OUI:A0681C*
 OUI:A0687E*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:A06974*
+ ID_OUI_FROM_DATABASE=Honor Device Co., Ltd.
+
 OUI:A06986*
  ID_OUI_FROM_DATABASE=Wellav Technologies Ltd
 
@@ -85820,9 +87116,15 @@ OUI:A075EA*
 OUI:A0764E*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
+OUI:A07751*
+ ID_OUI_FROM_DATABASE=ASMedia Technology Inc.
+
 OUI:A07771*
  ID_OUI_FROM_DATABASE=Vialis BV
 
+OUI:A07817*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:A078BA*
  ID_OUI_FROM_DATABASE=Pantech Co., Ltd.
 
@@ -85937,6 +87239,9 @@ OUI:A09DC1*
 OUI:A09E1A*
  ID_OUI_FROM_DATABASE=Polar Electro Oy
 
+OUI:A09F10*
+ ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD
+
 OUI:A0A130*
  ID_OUI_FROM_DATABASE=DLI Taiwan Branch office
 
@@ -86438,6 +87743,9 @@ OUI:A416E7*
 OUI:A41731*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:A4178B*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:A41791*
  ID_OUI_FROM_DATABASE=Shenzhen Decnta Technology Co.,LTD.
 
@@ -86805,7 +88113,7 @@ OUI:A46706*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
 OUI:A468BC*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Oakley Inc.
 
 OUI:A46C2A*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
@@ -86816,6 +88124,9 @@ OUI:A46CC1*
 OUI:A46CF1*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:A46DA4*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:A46E79*
  ID_OUI_FROM_DATABASE=DFT System Co.Ltd
 
@@ -86864,6 +88175,9 @@ OUI:A47C1F*
 OUI:A47CC9*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:A47D9F*
+ ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD
+
 OUI:A47E39*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -86927,6 +88241,9 @@ OUI:A4934C*
 OUI:A49426*
  ID_OUI_FROM_DATABASE=Elgama-Elektronika Ltd.
 
+OUI:A49733*
+ ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP
+
 OUI:A4975C*
  ID_OUI_FROM_DATABASE=VTech Telecommunications Ltd.
 
@@ -86990,6 +88307,9 @@ OUI:A4A6A9*
 OUI:A4A80F*
  ID_OUI_FROM_DATABASE=Shenzhen Coship Electronics Co., Ltd.
 
+OUI:A4AAFE*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:A4AC0F*
  ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
 
@@ -87116,6 +88436,9 @@ OUI:A4CAA0*
 OUI:A4CC32*
  ID_OUI_FROM_DATABASE=Inficomm Co., Ltd
 
+OUI:A4CCB9*
+ ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd.
+
 OUI:A4CD23*
  ID_OUI_FROM_DATABASE=Shenzhenshi Xinzhongxin  Co., Ltd
 
@@ -87353,6 +88676,9 @@ OUI:A4F522*
 OUI:A4F7D0*
  ID_OUI_FROM_DATABASE=LAN Accessories Co., Ltd.
 
+OUI:A4F9E4*
+ ID_OUI_FROM_DATABASE=AirVine Scientific, Inc.
+
 OUI:A4FA76*
  ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
 
@@ -87473,6 +88799,9 @@ OUI:A82BCD*
 OUI:A82BD6*
  ID_OUI_FROM_DATABASE=Shina System Co., Ltd
 
+OUI:A8301C*
+ ID_OUI_FROM_DATABASE=Qingdao Intelligent&Precise Electronics Co.,Ltd.
+
 OUI:A830AD*
  ID_OUI_FROM_DATABASE=WEIFANG GOERTEK ELECTRONICS CO.,LTD
 
@@ -87554,6 +88883,9 @@ OUI:A84025*
 OUI:A84041*
  ID_OUI_FROM_DATABASE=Dragino Technology Co., Limited
 
+OUI:A8407D*
+ ID_OUI_FROM_DATABASE=GD Midea Air-Conditioning Equipment Co.,Ltd.
+
 OUI:A84122*
  ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co.,Ltd.
 
@@ -87677,6 +89009,9 @@ OUI:A86D5F*
 OUI:A86DAA*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:A86E4E*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:A8705D*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -87689,6 +89024,9 @@ OUI:A87285*
 OUI:A8741D*
  ID_OUI_FROM_DATABASE=PHOENIX CONTACT Electronics GmbH
 
+OUI:A87484*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:A875D6*
  ID_OUI_FROM_DATABASE=FreeTek International Co., Ltd.
 
@@ -87716,6 +89054,9 @@ OUI:A87EEA*
 OUI:A88038*
  ID_OUI_FROM_DATABASE=ShenZhen MovingComm Technology Co., Limited
 
+OUI:A8817E*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:A88195*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -87800,6 +89141,9 @@ OUI:A89969*
 OUI:A89A93*
  ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
 
+OUI:A89AD7*
+ ID_OUI_FROM_DATABASE=Nokia
+
 OUI:A89B10*
  ID_OUI_FROM_DATABASE=inMotion Ltd.
 
@@ -87848,6 +89192,9 @@ OUI:A8A795*
 OUI:A8AD3D*
  ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd
 
+OUI:A8B088*
+ ID_OUI_FROM_DATABASE=eero inc.
+
 OUI:A8B0AE*
  ID_OUI_FROM_DATABASE=LEONI
 
@@ -87956,6 +89303,9 @@ OUI:A8D88A*
 OUI:A8DA01*
  ID_OUI_FROM_DATABASE=Shenzhen NUOLIJIA Digital Technology Co.,Ltd
 
+OUI:A8DA0C*
+ ID_OUI_FROM_DATABASE=SERVERCOM (INDIA) PRIVATE LIMITED
+
 OUI:A8DB03*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -88088,6 +89438,9 @@ OUI:AC11D3*
 OUI:AC1203*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:AC122F*
+ ID_OUI_FROM_DATABASE=Fantasia Trading LLC
+
 OUI:AC1461*
  ID_OUI_FROM_DATABASE=ATAW  Co., Ltd.
 
@@ -88223,6 +89576,9 @@ OUI:AC2FA8*
 OUI:AC319D*
  ID_OUI_FROM_DATABASE=Shenzhen TG-NET Botone Technology Co.,Ltd.
 
+OUI:AC3328*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:AC34CB*
  ID_OUI_FROM_DATABASE=Shanhai GBCOM Communication Technology Co. Ltd
 
@@ -88235,6 +89591,9 @@ OUI:AC3613*
 OUI:AC3651*
  ID_OUI_FROM_DATABASE=Jiangsu Hengtong Terahertz Technology Co., Ltd.
 
+OUI:AC3728*
+ ID_OUI_FROM_DATABASE=Taicang T&W Electronics
+
 OUI:AC3743*
  ID_OUI_FROM_DATABASE=HTC Corporation
 
@@ -88286,6 +89645,9 @@ OUI:AC4330*
 OUI:AC44F2*
  ID_OUI_FROM_DATABASE=YAMAHA CORPORATION
 
+OUI:AC471B*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:AC4723*
  ID_OUI_FROM_DATABASE=Genelec
 
@@ -88457,9 +89819,15 @@ OUI:AC675D*
 OUI:AC676F*
  ID_OUI_FROM_DATABASE=Electrocompaniet A.S.
 
+OUI:AC6784*
+ ID_OUI_FROM_DATABASE=Google, Inc.
+
 OUI:AC67B2*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
+OUI:AC6AA3*
+ ID_OUI_FROM_DATABASE=Shenzhen Kertong Technology Co.,Ltd
+
 OUI:AC6B0F*
  ID_OUI_FROM_DATABASE=CADENCE DESIGN SYSTEMS INC
 
@@ -88500,7 +89868,7 @@ OUI:AC7A42*
  ID_OUI_FROM_DATABASE=iConnectivity
 
 OUI:AC7A4D*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:AC7A56*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
@@ -88781,6 +90149,9 @@ OUI:ACDB48*
 OUI:ACDBDA*
  ID_OUI_FROM_DATABASE=Shenzhen Geniatech Inc, Ltd
 
+OUI:ACDCCA*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:ACDCE5*
  ID_OUI_FROM_DATABASE=Procter & Gamble Company
 
@@ -88875,7 +90246,7 @@ OUI:ACF7F3*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
 OUI:ACF85C*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Chengdu Higon Integrated Circuit Design Co,. Ltd.
 
 OUI:ACF8CC*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
@@ -88886,6 +90257,9 @@ OUI:ACF970*
 OUI:ACF97E*
  ID_OUI_FROM_DATABASE=ELESYS INC.
 
+OUI:ACFAA5*
+ ID_OUI_FROM_DATABASE=digitron
+
 OUI:ACFD93*
  ID_OUI_FROM_DATABASE=WEIFANG GOERTEK ELECTRONICS CO.,LTD
 
@@ -89096,6 +90470,9 @@ OUI:B04515*
 OUI:B04519*
  ID_OUI_FROM_DATABASE=TCT mobile ltd
 
+OUI:B04530*
+ ID_OUI_FROM_DATABASE=BSkyB Ltd
+
 OUI:B04545*
  ID_OUI_FROM_DATABASE=YACOUB Automation GmbH
 
@@ -89114,6 +90491,9 @@ OUI:B0487A*
 OUI:B0495F*
  ID_OUI_FROM_DATABASE=OMRON HEALTHCARE Co., Ltd.
 
+OUI:B04A39*
+ ID_OUI_FROM_DATABASE=Beijing Roborock Technology Co., Ltd.
+
 OUI:B04BBF*
  ID_OUI_FROM_DATABASE=PT HAN SUNG ELECTORONICS INDONESIA
 
@@ -89288,6 +90668,9 @@ OUI:B089C2*
 OUI:B08BCF*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:B08C75*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:B08E1A*
  ID_OUI_FROM_DATABASE=URadio Systems Co., Ltd
 
@@ -89330,6 +90713,9 @@ OUI:B0982B*
 OUI:B0989F*
  ID_OUI_FROM_DATABASE=LG CNS
 
+OUI:B098BC*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:B09928*
  ID_OUI_FROM_DATABASE=FUJITSU LIMITED
 
@@ -89357,6 +90743,9 @@ OUI:B0A454*
 OUI:B0A460*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:B0A651*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:B0A6F5*
  ID_OUI_FROM_DATABASE=Xaptum, Inc.
 
@@ -89474,6 +90863,9 @@ OUI:B0B98A*
 OUI:B0BB8B*
  ID_OUI_FROM_DATABASE=WAVETEL TECHNOLOGY LIMITED
 
+OUI:B0BBE5*
+ ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
+
 OUI:B0BD6D*
  ID_OUI_FROM_DATABASE=Echostreams Innovative Solutions
 
@@ -89510,6 +90902,9 @@ OUI:B0C46C*
 OUI:B0C4E7*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:B0C53C*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:B0C554*
  ID_OUI_FROM_DATABASE=D-Link International
 
@@ -89675,6 +91070,9 @@ OUI:B0EC71*
 OUI:B0EC8F*
  ID_OUI_FROM_DATABASE=GMX SAS
 
+OUI:B0ECDD*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:B0ECE1*
  ID_OUI_FROM_DATABASE=Private
 
@@ -89813,6 +91211,9 @@ OUI:B40E96*
 OUI:B40EDC*
  ID_OUI_FROM_DATABASE=LG-Ericsson Co.,Ltd.
 
+OUI:B40EDE*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:B40F3B*
  ID_OUI_FROM_DATABASE=Tenda Technology Co.,Ltd.Dongguan branch
 
@@ -89837,6 +91238,9 @@ OUI:B418D1*
 OUI:B41A1D*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:B41BB0*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:B41C30*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -90089,6 +91493,9 @@ OUI:B45570*
 OUI:B456B9*
  ID_OUI_FROM_DATABASE=Teraspek Technologies Co.,Ltd
 
+OUI:B456E3*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:B45861*
  ID_OUI_FROM_DATABASE=CRemote, LLC
 
@@ -90236,6 +91643,9 @@ OUI:B49A95*
 OUI:B49CDF*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:B49D02*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:B49D0B*
  ID_OUI_FROM_DATABASE=BQ
 
@@ -90398,6 +91808,9 @@ OUI:B4B859*
 OUI:B4B88D*
  ID_OUI_FROM_DATABASE=Thuh Company
 
+OUI:B4BA12*
+ ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co.,Ltd.
+
 OUI:B4BC7C*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
@@ -90540,7 +91953,7 @@ OUI:B4E9B0*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
 OUI:B4EC02*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:B4ECF2*
  ID_OUI_FROM_DATABASE=Shanghai Listent Medical Tech Co., Ltd.
@@ -90602,6 +92015,9 @@ OUI:B4F81E*
 OUI:B4F949*
  ID_OUI_FROM_DATABASE=optilink networks pvt ltd
 
+OUI:B4FBE3*
+ ID_OUI_FROM_DATABASE=AltoBeam (China) Inc.
+
 OUI:B4FBE4*
  ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc.
 
@@ -90614,6 +92030,9 @@ OUI:B4FC75*
 OUI:B4FE8C*
  ID_OUI_FROM_DATABASE=Centro Sicurezza Italia SpA
 
+OUI:B4FF98*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:B80018*
  ID_OUI_FROM_DATABASE=Htel
 
@@ -90650,6 +92069,9 @@ OUI:B80B9D*
 OUI:B810D4*
  ID_OUI_FROM_DATABASE=Masimo Corporation
 
+OUI:B8114B*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:B813E9*
  ID_OUI_FROM_DATABASE=Trace Live Network
 
@@ -90725,6 +92147,9 @@ OUI:B82ADC*
 OUI:B82CA0*
  ID_OUI_FROM_DATABASE=Resideo
 
+OUI:B82D28*
+ ID_OUI_FROM_DATABASE=AMPAK Technology,Inc.
+
 OUI:B82FCB*
  ID_OUI_FROM_DATABASE=CMS Electracom
 
@@ -90779,6 +92204,9 @@ OUI:B843E4*
 OUI:B844D9*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:B8477A*
+ ID_OUI_FROM_DATABASE=Dasan Electron Co., Ltd.
+
 OUI:B847C6*
  ID_OUI_FROM_DATABASE=SanJet Technology Corp.
 
@@ -90833,6 +92261,9 @@ OUI:B85E7B*
 OUI:B85F98*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
+OUI:B85FB0*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:B86091*
  ID_OUI_FROM_DATABASE=Onnet Technologies and Innovations LLC
 
@@ -90941,6 +92372,9 @@ OUI:B88687*
 OUI:B8871E*
  ID_OUI_FROM_DATABASE=Good Mind Industries Co., Ltd.
 
+OUI:B8876E*
+ ID_OUI_FROM_DATABASE=Yandex Services AG
+
 OUI:B887A8*
  ID_OUI_FROM_DATABASE=Step Ahead Innovations Inc.
 
@@ -91064,6 +92498,9 @@ OUI:B8AC6F*
 OUI:B8AD3E*
  ID_OUI_FROM_DATABASE=BLUECOM
 
+OUI:B8AE1C*
+ ID_OUI_FROM_DATABASE=Smart Cube., Ltd
+
 OUI:B8AE6E*
  ID_OUI_FROM_DATABASE=Nintendo Co., Ltd.
 
@@ -91638,7 +93075,7 @@ OUI:BC4101*
  ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp.
 
 OUI:BC428C*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:BC4377*
  ID_OUI_FROM_DATABASE=Hang Zhou Huite Technology Co.,ltd.
@@ -91706,6 +93143,9 @@ OUI:BC54FC*
 OUI:BC5A56*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:BC5BD5*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:BC5C4C*
  ID_OUI_FROM_DATABASE=ELECOM CO.,LTD.
 
@@ -91730,6 +93170,9 @@ OUI:BC620E*
 OUI:BC629F*
  ID_OUI_FROM_DATABASE=Telenet Systems P. Ltd.
 
+OUI:BC62CE*
+ ID_OUI_FROM_DATABASE=SHENZHEN NETIS TECHNOLOGY CO.,LTD
+
 OUI:BC62D2*
  ID_OUI_FROM_DATABASE=Genexis International B.V.
 
@@ -91796,6 +93239,9 @@ OUI:BC6778*
 OUI:BC6784*
  ID_OUI_FROM_DATABASE=Environics Oy
 
+OUI:BC69CB*
+ ID_OUI_FROM_DATABASE=Panasonic Life Solutions Networks Co., Ltd.
+
 OUI:BC6A16*
  ID_OUI_FROM_DATABASE=tdvine
 
@@ -91830,7 +93276,7 @@ OUI:BC74D7*
  ID_OUI_FROM_DATABASE=HangZhou JuRu Technology CO.,LTD
 
 OUI:BC7536*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:BC7574*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -91976,6 +93422,9 @@ OUI:BC9740D*
 OUI:BC9740E*
  ID_OUI_FROM_DATABASE=B4ComTechnologies LLC
 
+OUI:BC9789*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:BC97E1*
  ID_OUI_FROM_DATABASE=Broadcom Limited
 
@@ -91988,6 +93437,9 @@ OUI:BC98DF*
 OUI:BC9911*
  ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
 
+OUI:BC9930*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:BC99BC*
  ID_OUI_FROM_DATABASE=FonSee Technology Inc.
 
@@ -92312,6 +93764,9 @@ OUI:C02250*
 OUI:C02506*
  ID_OUI_FROM_DATABASE=AVM GmbH
 
+OUI:C0252F*
+ ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.
+
 OUI:C0255C*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -92357,6 +93812,9 @@ OUI:C02FF1*
 OUI:C0335E*
  ID_OUI_FROM_DATABASE=Microsoft
 
+OUI:C033DA*
+ ID_OUI_FROM_DATABASE=Shenzhen JRUN Technologies CO., LTD
+
 OUI:C034B4*
  ID_OUI_FROM_DATABASE=Gigastone Corporation
 
@@ -92387,6 +93845,9 @@ OUI:C0395A*
 OUI:C03B8F*
  ID_OUI_FROM_DATABASE=Minicom Digital Signage
 
+OUI:C03C59*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:C03D03*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -92411,6 +93872,9 @@ OUI:C03F2A*
 OUI:C03FD5*
  ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd.
 
+OUI:C03FDD*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C04004*
  ID_OUI_FROM_DATABASE=Medicaroid Corporation
 
@@ -92558,6 +94022,9 @@ OUI:C0742B*
 OUI:C074AD*
  ID_OUI_FROM_DATABASE=Grandstream Networks, Inc.
 
+OUI:C07831*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:C07878*
  ID_OUI_FROM_DATABASE=FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.
 
@@ -92678,6 +94145,12 @@ OUI:C09132*
 OUI:C09134*
  ID_OUI_FROM_DATABASE=ProCurve Networking by HP
 
+OUI:C09435*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
+OUI:C094AD*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:C095DA*
  ID_OUI_FROM_DATABASE=NXP India Private Limited
 
@@ -92894,6 +94367,9 @@ OUI:C0C946*
 OUI:C0C976*
  ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp.
 
+OUI:C0C9E3*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:C0CB38*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
@@ -93122,6 +94598,9 @@ OUI:C40938*
 OUI:C40ACB*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:C40B31*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:C40BCB*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -93158,6 +94637,9 @@ OUI:C416FA*
 OUI:C417FE*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:C418E9*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:C4198B*
  ID_OUI_FROM_DATABASE=Dominion Voting Systems Corporation
 
@@ -93167,6 +94649,9 @@ OUI:C419D1*
 OUI:C419EC*
  ID_OUI_FROM_DATABASE=Qualisys AB
 
+OUI:C41C9C*
+ ID_OUI_FROM_DATABASE=JiQiDao
+
 OUI:C41CFF*
  ID_OUI_FROM_DATABASE=Vizio, Inc
 
@@ -93191,6 +94676,9 @@ OUI:C42456*
 OUI:C42628*
  ID_OUI_FROM_DATABASE=Airo Wireless
 
+OUI:C4278C*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:C42795*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
@@ -93239,6 +94727,9 @@ OUI:C4366C*
 OUI:C436DA*
  ID_OUI_FROM_DATABASE=Rusteletech Ltd.
 
+OUI:C43772*
+ ID_OUI_FROM_DATABASE=Virtuozzo International GmbH
+
 OUI:C438D3*
  ID_OUI_FROM_DATABASE=TAGATEC CO.,LTD
 
@@ -93257,15 +94748,24 @@ OUI:C43ABE*
 OUI:C43C3C*
  ID_OUI_FROM_DATABASE=CYBELEC SA
 
+OUI:C43CEA*
+ ID_OUI_FROM_DATABASE=BUFFALO.INC
+
 OUI:C43DC7*
  ID_OUI_FROM_DATABASE=NETGEAR
 
 OUI:C44044*
  ID_OUI_FROM_DATABASE=RackTop Systems Inc.
 
+OUI:C440F6*
+ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
+
 OUI:C4411E*
  ID_OUI_FROM_DATABASE=Belkin International Inc.
 
+OUI:C44137*
+ ID_OUI_FROM_DATABASE=Quectel Wireless Solutions Co., Ltd.
+
 OUI:C44202*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -93350,6 +94850,9 @@ OUI:C458C2*
 OUI:C45976*
  ID_OUI_FROM_DATABASE=Fugoo Coorporation
 
+OUI:C45A86*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:C45BF7*
  ID_OUI_FROM_DATABASE=ants
 
@@ -93401,6 +94904,9 @@ OUI:C468D0*
 OUI:C4693E*
  ID_OUI_FROM_DATABASE=Turbulence Design Inc.
 
+OUI:C469F0*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C46AB7*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -93659,6 +95165,9 @@ OUI:C4A366*
 OUI:C4A402*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:C4A72B*
+ ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD
+
 OUI:C4A81D*
  ID_OUI_FROM_DATABASE=D-Link International
 
@@ -93749,6 +95258,9 @@ OUI:C4C9EC*
 OUI:C4CAD9*
  ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
 
+OUI:C4CB54*
+ ID_OUI_FROM_DATABASE=Fibocom Auto Inc.
+
 OUI:C4CB6B*
  ID_OUI_FROM_DATABASE=Airista Flow, Inc.
 
@@ -93785,6 +95297,9 @@ OUI:C4DA7D*
 OUI:C4DD57*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
+OUI:C4DE7B*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:C4E032*
  ID_OUI_FROM_DATABASE=IEEE 1904.1 Working Group
 
@@ -93863,6 +95378,9 @@ OUI:C4F7D5*
 OUI:C4F839*
  ID_OUI_FROM_DATABASE=Actia Automotive
 
+OUI:C4FBAA*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C4FCE4*
  ID_OUI_FROM_DATABASE=DishTV NZ Ltd
 
@@ -94532,6 +96050,9 @@ OUI:C8B5AD*
 OUI:C8B5B7*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:C8B6D3*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C8BA94*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -95024,6 +96545,9 @@ OUI:CC3A61*
 OUI:CC3ADF*
  ID_OUI_FROM_DATABASE=Private
 
+OUI:CC3B27*
+ ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED
+
 OUI:CC3B3E*
  ID_OUI_FROM_DATABASE=Lester Electrical
 
@@ -95093,6 +96617,48 @@ OUI:CC4E24*
 OUI:CC4EEC*
  ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
 
+OUI:CC4F5C1*
+ ID_OUI_FROM_DATABASE=lesswire GmbH
+
+OUI:CC4F5C2*
+ ID_OUI_FROM_DATABASE=MatchX GmbH
+
+OUI:CC4F5C3*
+ ID_OUI_FROM_DATABASE=Shanghai Zenchant Electornics Co.,LTD
+
+OUI:CC4F5C4*
+ ID_OUI_FROM_DATABASE=Spark Biomedical
+
+OUI:CC4F5C5*
+ ID_OUI_FROM_DATABASE=Kymati GmbH
+
+OUI:CC4F5C6*
+ ID_OUI_FROM_DATABASE=Watertech S.p.A.
+
+OUI:CC4F5C7*
+ ID_OUI_FROM_DATABASE=Smiths US Innovation LLC
+
+OUI:CC4F5C8*
+ ID_OUI_FROM_DATABASE=Feelmore Labs
+
+OUI:CC4F5C9*
+ ID_OUI_FROM_DATABASE=Dtrovision
+
+OUI:CC4F5CA*
+ ID_OUI_FROM_DATABASE=AZ-TECHNOLOGY SDN BHD
+
+OUI:CC4F5CB*
+ ID_OUI_FROM_DATABASE=Ontex BV
+
+OUI:CC4F5CC*
+ ID_OUI_FROM_DATABASE=Beijing Cotytech Technology Co.,LTD.
+
+OUI:CC4F5CD*
+ ID_OUI_FROM_DATABASE=Beijing Neutron Technology CO.,LTD.
+
+OUI:CC4F5CE*
+ ID_OUI_FROM_DATABASE=Buttons (Beijing) Technology Limited
+
 OUI:CC500A*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
@@ -95642,6 +97208,9 @@ OUI:CCDC55*
 OUI:CCE0C3*
  ID_OUI_FROM_DATABASE=EXTEN Technologies, Inc.
 
+OUI:CCE0DA*
+ ID_OUI_FROM_DATABASE=Baidu Online Network Technology (Beijing) Co., Ltd
+
 OUI:CCE17F*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
@@ -95690,6 +97259,9 @@ OUI:CCF411*
 OUI:CCF538*
  ID_OUI_FROM_DATABASE=3isysnetworks
 
+OUI:CCF55F*
+ ID_OUI_FROM_DATABASE=E FOCUS INSTRUMENTS INDIA PRIVATE LIMITED
+
 OUI:CCF67A*
  ID_OUI_FROM_DATABASE=Ayecka Communication Systems LTD
 
@@ -95855,6 +97427,9 @@ OUI:D01C3C*
 OUI:D01CBB*
  ID_OUI_FROM_DATABASE=Beijing Ctimes Digital Technology Co., Ltd.
 
+OUI:D021AC*
+ ID_OUI_FROM_DATABASE=Yo Labs LLC
+
 OUI:D021F9*
  ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc.
 
@@ -95933,6 +97508,9 @@ OUI:D02C45*
 OUI:D02DB3*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:D02EAB*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:D03110*
  ID_OUI_FROM_DATABASE=Ingenic Semiconductor Co.,Ltd
 
@@ -96017,6 +97595,9 @@ OUI:D05349*
 OUI:D0542D*
  ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd.
 
+OUI:D05509*
+ ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd
+
 OUI:D055B2*
  ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
 
@@ -96047,6 +97628,9 @@ OUI:D058C0*
 OUI:D058FC*
  ID_OUI_FROM_DATABASE=BSkyB Ltd
 
+OUI:D05919*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:D05995*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
@@ -96398,6 +97982,9 @@ OUI:D0BAE4*
 OUI:D0BB80*
  ID_OUI_FROM_DATABASE=SHL Telemedicine International Ltd.
 
+OUI:D0BCC1*
+ ID_OUI_FROM_DATABASE=WEIFANG GOERTEK ELECTRONICS CO.,LTD
+
 OUI:D0BD01*
  ID_OUI_FROM_DATABASE=DS International
 
@@ -96419,6 +98006,9 @@ OUI:D0C1B1*
 OUI:D0C282*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:D0C31E*
+ ID_OUI_FROM_DATABASE=JUNGJIN Electronics Co.,Ltd
+
 OUI:D0C42F*
  ID_OUI_FROM_DATABASE=Tamagawa Seiki Co.,Ltd.
 
@@ -96716,6 +98306,9 @@ OUI:D41A3F*
 OUI:D41AC8*
  ID_OUI_FROM_DATABASE=Nippon Printer Engineering
 
+OUI:D41B81*
+ ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
+
 OUI:D41C1C*
  ID_OUI_FROM_DATABASE=RCF S.P.A.
 
@@ -96914,6 +98507,9 @@ OUI:D44CA7*
 OUI:D44DA4*
  ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
 
+OUI:D44F67*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:D44F68*
  ID_OUI_FROM_DATABASE=Eidetic Communications Inc
 
@@ -97076,6 +98672,9 @@ OUI:D47226*
 OUI:D4741B*
  ID_OUI_FROM_DATABASE=Beijing HuaDa ZhiBao Electronic System Co.,Ltd.
 
+OUI:D476A0*
+ ID_OUI_FROM_DATABASE=Fortinet, Inc.
+
 OUI:D476EA*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -97154,6 +98753,9 @@ OUI:D47C44E*
 OUI:D47DFC*
  ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED
 
+OUI:D47EE4*
+ ID_OUI_FROM_DATABASE=China Mobile IOT Company Limited
+
 OUI:D481CA*
  ID_OUI_FROM_DATABASE=iDevices, LLC
 
@@ -97199,6 +98801,9 @@ OUI:D4909C*
 OUI:D490E0*
  ID_OUI_FROM_DATABASE=Topcon Electronics GmbH & Co. KG
 
+OUI:D4910F*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:D491AF*
  ID_OUI_FROM_DATABASE=Electroacustica General Iberica, S.A.
 
@@ -97571,6 +99176,9 @@ OUI:D80DE3*
 OUI:D80F99*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:D810CB*
+ ID_OUI_FROM_DATABASE=Andrea Informatique
+
 OUI:D81265*
  ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
 
@@ -97697,6 +99305,9 @@ OUI:D8337F*
 OUI:D834EE*
  ID_OUI_FROM_DATABASE=Stem Audio
 
+OUI:D8373B*
+ ID_OUI_FROM_DATABASE=Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd
+
 OUI:D837BE*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT
 
@@ -98189,6 +99800,9 @@ OUI:D8CA06*
 OUI:D8CB8A*
  ID_OUI_FROM_DATABASE=Micro-Star INTL CO., LTD.
 
+OUI:D8CC98*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:D8CE3A*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -98309,6 +99923,9 @@ OUI:D8F1F0*
 OUI:D8F2CA*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:D8F3BC*
+ ID_OUI_FROM_DATABASE=Liteon Technology Corporation
+
 OUI:D8F3DB*
  ID_OUI_FROM_DATABASE=Post CH AG
 
@@ -98609,6 +100226,51 @@ OUI:DC49C9*
 OUI:DC4A3E*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
+OUI:DC4A9E0*
+ ID_OUI_FROM_DATABASE=Dongguan Huili electroacoustic Industrial Co.,ltd
+
+OUI:DC4A9E1*
+ ID_OUI_FROM_DATABASE=Advanced Electronics Ltd
+
+OUI:DC4A9E2*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
+OUI:DC4A9E3*
+ ID_OUI_FROM_DATABASE=LEACH INTERNATIONAL EUROPE
+
+OUI:DC4A9E4*
+ ID_OUI_FROM_DATABASE=ADIAL
+
+OUI:DC4A9E5*
+ ID_OUI_FROM_DATABASE=Nuove Tecnologie srl
+
+OUI:DC4A9E6*
+ ID_OUI_FROM_DATABASE=TATTILE SRL
+
+OUI:DC4A9E7*
+ ID_OUI_FROM_DATABASE=Astrogate Inc.
+
+OUI:DC4A9E8*
+ ID_OUI_FROM_DATABASE=Methodex Systems Pvt. Ltd.
+
+OUI:DC4A9E9*
+ ID_OUI_FROM_DATABASE=AiSight GmbH
+
+OUI:DC4A9EA*
+ ID_OUI_FROM_DATABASE=LongSung Technology (Shanghai) Co.,Ltd.
+
+OUI:DC4A9EB*
+ ID_OUI_FROM_DATABASE=Maxvision Technology Corp.
+
+OUI:DC4A9EC*
+ ID_OUI_FROM_DATABASE=HEFEI DATANG STORAGE TECHNOLOGY CO.,LTD
+
+OUI:DC4A9ED*
+ ID_OUI_FROM_DATABASE=HAPPIEST BABY INC.
+
+OUI:DC4A9EE*
+ ID_OUI_FROM_DATABASE=SES-imagotag Deutschland GmbH
+
 OUI:DC4BDD*
  ID_OUI_FROM_DATABASE=Shenzhen SuperElectron Technology Co.,Ltd.
 
@@ -98666,6 +100328,9 @@ OUI:DC5E36*
 OUI:DC60A1*
  ID_OUI_FROM_DATABASE=Teledyne DALSA Professional Imaging
 
+OUI:DC6373*
+ ID_OUI_FROM_DATABASE=OBARA KOREA
+
 OUI:DC647C*
  ID_OUI_FROM_DATABASE=C.R.S. iiMotion GmbH
 
@@ -98756,6 +100421,9 @@ OUI:DC8983*
 OUI:DC8B28*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:DC8C1B*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:DC8C37*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -98783,6 +100451,9 @@ OUI:DC9B1E*
 OUI:DC9B9C*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:DC9BD6*
+ ID_OUI_FROM_DATABASE=TCT mobile ltd
+
 OUI:DC9C52*
  ID_OUI_FROM_DATABASE=Sapphire Technology Limited.
 
@@ -98861,6 +100532,12 @@ OUI:DCB4AC*
 OUI:DCB4C4*
  ID_OUI_FROM_DATABASE=Microsoft XCG
 
+OUI:DCB72E*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
+OUI:DCB7FC*
+ ID_OUI_FROM_DATABASE=Alps Electric (Ireland) Ltd
+
 OUI:DCB808*
  ID_OUI_FROM_DATABASE=Extreme Networks, Inc.
 
@@ -99053,6 +100730,9 @@ OUI:DCE71C*
 OUI:DCE838*
  ID_OUI_FROM_DATABASE=CK Telecom (Shenzhen) Limited
 
+OUI:DCE994*
+ ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.
+
 OUI:DCEB53*
  ID_OUI_FROM_DATABASE=Wuhan QianXiao Elecronic Technology CO.,LTD
 
@@ -99203,6 +100883,9 @@ OUI:E01C41*
 OUI:E01CEE*
  ID_OUI_FROM_DATABASE=Bravo Tech, Inc.
 
+OUI:E01CFC*
+ ID_OUI_FROM_DATABASE=D-Link International
+
 OUI:E01D38*
  ID_OUI_FROM_DATABASE=Beijing HuaqinWorld Technology Co.,Ltd
 
@@ -99218,6 +100901,9 @@ OUI:E01F0A*
 OUI:E01F88*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
+OUI:E01FED*
+ ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
+
 OUI:E02202*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -99257,6 +100943,9 @@ OUI:E02AE6*
 OUI:E02B96*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:E02BE9*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:E02CB2*
  ID_OUI_FROM_DATABASE=Lenovo Mobile Communication (Wuhan) Company Limited
 
@@ -99347,6 +101036,9 @@ OUI:E049ED*
 OUI:E04B45*
  ID_OUI_FROM_DATABASE=Hi-P Electronics Pte Ltd
 
+OUI:E04BA6*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:E04F43*
  ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd.
 
@@ -99479,11 +101171,14 @@ OUI:E06995*
 OUI:E06CA6*
  ID_OUI_FROM_DATABASE=Creotech Instruments S.A.
 
+OUI:E06D17*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:E0735F*
  ID_OUI_FROM_DATABASE=NUCOM
 
 OUI:E0750A*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:E0757D*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
@@ -99491,6 +101186,9 @@ OUI:E0757D*
 OUI:E076D0*
  ID_OUI_FROM_DATABASE=AMPAK Technology, Inc.
 
+OUI:E07726*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:E078A3*
  ID_OUI_FROM_DATABASE=Shanghai Winner Information Technology Co.,Inc
 
@@ -99545,6 +101243,9 @@ OUI:E08E3C*
 OUI:E08FEC*
  ID_OUI_FROM_DATABASE=REPOTEC CO., LTD.
 
+OUI:E0913C*
+ ID_OUI_FROM_DATABASE=Kyeungin CNS Co., Ltd.
+
 OUI:E09153*
  ID_OUI_FROM_DATABASE=XAVi Technologies Corp.
 
@@ -99630,7 +101331,7 @@ OUI:E0ACF1*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
 OUI:E0AE5E*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:E0AEB2*
  ID_OUI_FROM_DATABASE=Bender GmbH &amp; Co.KG
@@ -99743,6 +101444,9 @@ OUI:E0C286*
 OUI:E0C2B7*
  ID_OUI_FROM_DATABASE=Masimo Corporation
 
+OUI:E0C377*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:E0C3F3*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -99860,9 +101564,18 @@ OUI:E0DCFF*
 OUI:E0DDC0*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
+OUI:E0E0C2*
+ ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd.
+
 OUI:E0E0FC*
  ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
 
+OUI:E0E1A9*
+ ID_OUI_FROM_DATABASE=Shenzhen Four Seas Global Link Network Technology Co., Ltd.
+
+OUI:E0E2E6*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:E0E5CF*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
@@ -100085,6 +101798,9 @@ OUI:E43022*
 OUI:E432CB*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:E433AE*
+ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
+
 OUI:E43493*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -100151,6 +101867,9 @@ OUI:E446DA*
 OUI:E44790*
  ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
 
+OUI:E44791*
+ ID_OUI_FROM_DATABASE=Iris ID Systems, Inc.
+
 OUI:E447B3*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -100382,6 +102101,9 @@ OUI:E48C0F*
 OUI:E48D8C*
  ID_OUI_FROM_DATABASE=Routerboard.com
 
+OUI:E48F1D*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:E48F34*
  ID_OUI_FROM_DATABASE=Vodafone Italia S.p.A.
 
@@ -100571,6 +102293,9 @@ OUI:E4C1F1*
 OUI:E4C2D1*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:E4C32A*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:E4C483*
  ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
 
@@ -100634,6 +102359,9 @@ OUI:E4D71D*
 OUI:E4DB6D*
  ID_OUI_FROM_DATABASE=Beijing Xiaomi Electronics Co., Ltd.
 
+OUI:E4DC43*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:E4DD79*
  ID_OUI_FROM_DATABASE=En-Vision America, Inc.
 
@@ -100676,6 +102404,9 @@ OUI:E4F042*
 OUI:E4F14C*
  ID_OUI_FROM_DATABASE=Private
 
+OUI:E4F1D4*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:E4F327*
  ID_OUI_FROM_DATABASE=ATOL LLC
 
@@ -100778,6 +102509,9 @@ OUI:E80945*
 OUI:E80959*
  ID_OUI_FROM_DATABASE=Guoguang Electric Co.,Ltd
 
+OUI:E80AEC*
+ ID_OUI_FROM_DATABASE=Jiangsu Hengtong Optic-Electric Co., LTD
+
 OUI:E80B13*
  ID_OUI_FROM_DATABASE=Akib Systems Taiwan, INC
 
@@ -100883,6 +102617,9 @@ OUI:E81CBA*
 OUI:E81DA8*
  ID_OUI_FROM_DATABASE=Ruckus Wireless
 
+OUI:E81E92*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:E820E2*
  ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
 
@@ -100973,6 +102710,9 @@ OUI:E8447E*
 OUI:E8481F*
  ID_OUI_FROM_DATABASE=Advanced Automotive Antennas
 
+OUI:E848B8*
+ ID_OUI_FROM_DATABASE=TP-Link Corporation Limited
+
 OUI:E84943*
  ID_OUI_FROM_DATABASE=YUGE Information technology Co. Ltd
 
@@ -100991,6 +102731,9 @@ OUI:E84E84*
 OUI:E84ECE*
  ID_OUI_FROM_DATABASE=Nintendo Co., Ltd.
 
+OUI:E84F4B*
+ ID_OUI_FROM_DATABASE=Shenzhen Delos Electronic Co., Ltd
+
 OUI:E8508B*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -101063,6 +102806,9 @@ OUI:E866C4*
 OUI:E86819*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:E868E7*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:E86A64*
  ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology co., ltd
 
@@ -101108,6 +102854,9 @@ OUI:E878A1*
 OUI:E87AF3*
  ID_OUI_FROM_DATABASE=S5 Tech S.r.l.
 
+OUI:E87F6B*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:E87F95*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -101123,6 +102872,9 @@ OUI:E88152*
 OUI:E8825B*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:E884A5*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:E884C6*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -101330,8 +103082,11 @@ OUI:E8C1D7*
 OUI:E8C229*
  ID_OUI_FROM_DATABASE=H-Displays (MSC) Bhd
 
+OUI:E8C2DD*
+ ID_OUI_FROM_DATABASE=Infinix mobility limited
+
 OUI:E8C320*
- ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd
+ ID_OUI_FROM_DATABASE=Austco Marketing & Service (USA) ltd.
 
 OUI:E8C417*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
@@ -101396,6 +103151,9 @@ OUI:E8DA96*
 OUI:E8DAAA*
  ID_OUI_FROM_DATABASE=VideoHome Technology Corp.
 
+OUI:E8DB84*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:E8DE00*
  ID_OUI_FROM_DATABASE=ChongQing GuanFang Technology Co.,LTD
 
@@ -101462,6 +103220,9 @@ OUI:E8EB11*
 OUI:E8EB1B*
  ID_OUI_FROM_DATABASE=Microchip Technology Inc.
 
+OUI:E8EB34*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:E8ECA3*
  ID_OUI_FROM_DATABASE=Dongguan Liesheng Electronic Co.Ltd
 
@@ -101531,6 +103292,9 @@ OUI:EC086B*
 OUI:EC0D9A*
  ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc.
 
+OUI:EC0DE4*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:EC0EC4*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
@@ -101762,6 +103526,9 @@ OUI:EC63E5*
 OUI:EC63ED*
  ID_OUI_FROM_DATABASE=Hyundai Autoever Corp.
 
+OUI:EC6488*
+ ID_OUI_FROM_DATABASE=Honor Device Co., Ltd.
+
 OUI:EC64E7*
  ID_OUI_FROM_DATABASE=MOCACARE Corporation
 
@@ -101813,6 +103580,9 @@ OUI:EC7D11*
 OUI:EC7D9D*
  ID_OUI_FROM_DATABASE=CPI
 
+OUI:EC7E91*
+ ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED
+
 OUI:EC7FC6*
  ID_OUI_FROM_DATABASE=ECCEL CORPORATION SAS
 
@@ -101960,6 +103730,9 @@ OUI:EC9F0DD*
 OUI:EC9F0DE*
  ID_OUI_FROM_DATABASE=MAX Technologies
 
+OUI:ECA1D1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:ECA29B*
  ID_OUI_FROM_DATABASE=Kemppi Oy
 
@@ -102035,6 +103808,9 @@ OUI:ECC01B*
 OUI:ECC06A*
  ID_OUI_FROM_DATABASE=PowerChord Group Limited
 
+OUI:ECC302*
+ ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
+
 OUI:ECC38A*
  ID_OUI_FROM_DATABASE=Accuenergy (CANADA) Inc
 
@@ -102047,12 +103823,18 @@ OUI:ECC57F*
 OUI:ECC882*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:ECC89C*
+ ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd.
+
 OUI:ECCB30*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
 OUI:ECCD6D*
  ID_OUI_FROM_DATABASE=Allied Telesis, Inc.
 
+OUI:ECCE13*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:ECCED7*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -102224,6 +104006,9 @@ OUI:F01090*
 OUI:F010AB*
  ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co., Ltd.
 
+OUI:F013C1*
+ ID_OUI_FROM_DATABASE=Hannto Technology Co., Ltd
+
 OUI:F013C3*
  ID_OUI_FROM_DATABASE=SHENZHEN FENDA TECHNOLOGY CO., LTD
 
@@ -102248,6 +104033,9 @@ OUI:F01C13*
 OUI:F01C2D*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:F01D2D*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:F01DBC*
  ID_OUI_FROM_DATABASE=Microsoft Corporation
 
@@ -102266,6 +104054,9 @@ OUI:F0224E*
 OUI:F02329*
  ID_OUI_FROM_DATABASE=SHOWA DENKI CO.,LTD.
 
+OUI:F023AE*
+ ID_OUI_FROM_DATABASE=AMPAK Technology,Inc.
+
 OUI:F023B90*
  ID_OUI_FROM_DATABASE=Aquametro AG
 
@@ -102353,6 +104144,9 @@ OUI:F02A61*
 OUI:F02E51*
  ID_OUI_FROM_DATABASE=Casa Systems
 
+OUI:F02F74*
+ ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+
 OUI:F02FA7*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -102480,7 +104274,7 @@ OUI:F04DA2*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
 OUI:F04F7C*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
 OUI:F05136*
  ID_OUI_FROM_DATABASE=TCT mobile ltd
@@ -102533,6 +104327,9 @@ OUI:F06281*
 OUI:F063F9*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:F06426*
+ ID_OUI_FROM_DATABASE=Extreme Networks, Inc.
+
 OUI:F065C2*
  ID_OUI_FROM_DATABASE=Yanfeng Visteon Electronics Technology (Shanghai) Co.,Ltd.
 
@@ -102714,7 +104511,7 @@ OUI:F09FFC*
  ID_OUI_FROM_DATABASE=SHARP Corporation
 
 OUI:F0A225*
- ID_OUI_FROM_DATABASE=Private
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
 OUI:F0A35A*
  ID_OUI_FROM_DATABASE=Apple, Inc.
@@ -102728,6 +104525,9 @@ OUI:F0A7B2*
 OUI:F0A968*
  ID_OUI_FROM_DATABASE=Antailiye Technology Co.,Ltd
 
+OUI:F0AA0B*
+ ID_OUI_FROM_DATABASE=Arra Networks/ Spectramesh
+
 OUI:F0AB54*
  ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO.,LTD.
 
@@ -102812,6 +104612,9 @@ OUI:F0B2E5*
 OUI:F0B31E*
  ID_OUI_FROM_DATABASE=Universal Electronics, Inc.
 
+OUI:F0B3EC*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:F0B429*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -103067,6 +104870,9 @@ OUI:F0F755*
 OUI:F0F7B3*
  ID_OUI_FROM_DATABASE=Phorm
 
+OUI:F0F7E7*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:F0F842*
  ID_OUI_FROM_DATABASE=KEEBOX, Inc.
 
@@ -103130,6 +104936,9 @@ OUI:F40A4A*
 OUI:F40B93*
  ID_OUI_FROM_DATABASE=BlackBerry RTS
 
+OUI:F40B9F*
+ ID_OUI_FROM_DATABASE=CIG SHANGHAI CO LTD
+
 OUI:F40E01*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -103274,6 +105083,9 @@ OUI:F4323D*
 OUI:F43328*
  ID_OUI_FROM_DATABASE=CIMCON Lighting Inc.
 
+OUI:F434F0*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:F436E1*
  ID_OUI_FROM_DATABASE=Abilis Systems SARL
 
@@ -103349,6 +105161,9 @@ OUI:F44E05*
 OUI:F44EFD*
  ID_OUI_FROM_DATABASE=Actions Semiconductor Co.,Ltd.(Cayman Islands)
 
+OUI:F44FD3*
+ ID_OUI_FROM_DATABASE=shenzhen hemuwei technology co.,ltd
+
 OUI:F450EB*
  ID_OUI_FROM_DATABASE=Telechips Inc
 
@@ -103412,6 +105227,9 @@ OUI:F46349*
 OUI:F4645D*
  ID_OUI_FROM_DATABASE=Toshiba
 
+OUI:F465A6*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:F4672D*
  ID_OUI_FROM_DATABASE=ShenZhen Topstar Technology Company
 
@@ -103484,6 +105302,9 @@ OUI:F46E95*
 OUI:F46F4E*
  ID_OUI_FROM_DATABASE=Echowell
 
+OUI:F46FED*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
 OUI:F470AB*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
@@ -104030,6 +105851,9 @@ OUI:F80D43*
 OUI:F80D60*
  ID_OUI_FROM_DATABASE=CANON INC.
 
+OUI:F80DAC*
+ ID_OUI_FROM_DATABASE=HP Inc.
+
 OUI:F80DEA*
  ID_OUI_FROM_DATABASE=ZyCast Technology Inc.
 
@@ -104234,6 +106058,12 @@ OUI:F8369B*
 OUI:F83880*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:F83B1D*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
+
+OUI:F83B7E*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:F83CBF*
  ID_OUI_FROM_DATABASE=BOTATO ELECTRONICS SDN BHD
 
@@ -104309,6 +106139,9 @@ OUI:F8516D*
 OUI:F852DF*
  ID_OUI_FROM_DATABASE=VNL Europe AB
 
+OUI:F85329*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:F854AF*
  ID_OUI_FROM_DATABASE=ECI Telecom Ltd.
 
@@ -104348,6 +106181,12 @@ OUI:F85C7D*
 OUI:F85E3C*
  ID_OUI_FROM_DATABASE=SHENZHEN ZHIBOTONG ELECTRONICS CO.,LTD
 
+OUI:F85E42*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
+
+OUI:F85EA0*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:F85F2A*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
@@ -104372,6 +106211,9 @@ OUI:F864B8*
 OUI:F86601*
  ID_OUI_FROM_DATABASE=Suzhou Chi-tek information technology Co., Ltd
 
+OUI:F8665A*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:F866D1*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
@@ -104390,6 +106232,9 @@ OUI:F86C03*
 OUI:F86CE1*
  ID_OUI_FROM_DATABASE=Taicang T&W Electronics
 
+OUI:F86D73*
+ ID_OUI_FROM_DATABASE=Zengge Co., Limited
+
 OUI:F86ECF*
  ID_OUI_FROM_DATABASE=Arcx Inc
 
@@ -104426,6 +106271,9 @@ OUI:F8769B*
 OUI:F877B8*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:F87A41*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:F87AEF*
  ID_OUI_FROM_DATABASE=Rosonix Technology, Inc.
 
@@ -104516,6 +106364,9 @@ OUI:F88B37*
 OUI:F88C1C*
  ID_OUI_FROM_DATABASE=KAISHUN ELECTRONIC TECHNOLOGY CO., LTD. BEIJING
 
+OUI:F88C21*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:F88DEF*
  ID_OUI_FROM_DATABASE=Tenebraex
 
@@ -104609,6 +106460,9 @@ OUI:F8A45F*
 OUI:F8A5C5*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:F8A73A*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:F8A763*
  ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd.
 
@@ -104648,6 +106502,9 @@ OUI:F8AFDB*
 OUI:F8B156*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
+OUI:F8B1DD*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
 OUI:F8B2F3*
  ID_OUI_FROM_DATABASE=GUANGZHOU BOSMA TECHNOLOGY CO.,LTD
 
@@ -104708,6 +106565,9 @@ OUI:F8B797*
 OUI:F8B7E2*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:F8B95A*
+ ID_OUI_FROM_DATABASE=LG Innotek
+
 OUI:F8BBBF*
  ID_OUI_FROM_DATABASE=eero inc.
 
@@ -104837,6 +106697,9 @@ OUI:F8DFE1*
 OUI:F8E079*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
+OUI:F8E43B*
+ ID_OUI_FROM_DATABASE=ASIX Electronics Corporation
+
 OUI:F8E44E*
  ID_OUI_FROM_DATABASE=MCOT INC.
 
@@ -105008,6 +106871,9 @@ OUI:FC183C*
 OUI:FC1910*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:FC1928*
+ ID_OUI_FROM_DATABASE=Actions Microelectronics Co., Ltd
+
 OUI:FC1999*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
@@ -105146,6 +107012,9 @@ OUI:FC455F*
 OUI:FC4596*
  ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD.
 
+OUI:FC45C3*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:FC48EF*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -105158,6 +107027,9 @@ OUI:FC4AE9*
 OUI:FC4B1C*
  ID_OUI_FROM_DATABASE=INTERSENSOR S.R.L.
 
+OUI:FC4B57*
+ ID_OUI_FROM_DATABASE=Peerless Instrument Division of Curtiss-Wright
+
 OUI:FC4BBC*
  ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd.
 
@@ -105219,7 +107091,7 @@ OUI:FC626E*
  ID_OUI_FROM_DATABASE=Beijing MDC Telecom
 
 OUI:FC62B9*
- ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO., LTD.
+ ID_OUI_FROM_DATABASE=ALPSALPINE CO,.LTD
 
 OUI:FC643A*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -105227,6 +107099,9 @@ OUI:FC643A*
 OUI:FC64BA*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
+OUI:FC65B3*
+ ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd.
+
 OUI:FC65DE*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
@@ -105239,6 +107114,9 @@ OUI:FC683E*
 OUI:FC6947*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:FC698C*
+ ID_OUI_FROM_DATABASE=ANDREAS STIHL AG & Co. KG
+
 OUI:FC6BF0*
  ID_OUI_FROM_DATABASE=TOPWELL INTERNATIONAL HOLDINDS LIMITED
 
@@ -105248,6 +107126,9 @@ OUI:FC6C31*
 OUI:FC6DC0*
  ID_OUI_FROM_DATABASE=BME CORPORATION
 
+OUI:FC6DD1*
+ ID_OUI_FROM_DATABASE=APRESIA Systems, Ltd.
+
 OUI:FC6FB7*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -105281,6 +107162,9 @@ OUI:FC7D6C*
 OUI:FC7F56*
  ID_OUI_FROM_DATABASE=CoSyst Control Systems GmbH
 
+OUI:FC7FF1*
+ ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
+
 OUI:FC8329*
  ID_OUI_FROM_DATABASE=Trei technics
 
@@ -105302,6 +107186,9 @@ OUI:FC8743*
 OUI:FC8B97*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT
 
+OUI:FC8D3D*
+ ID_OUI_FROM_DATABASE=Leapfive Tech. Ltd.
+
 OUI:FC8E5B*
  ID_OUI_FROM_DATABASE=China Mobile Iot Limited company
 
@@ -105344,6 +107231,9 @@ OUI:FC94E3*
 OUI:FC956A*
  ID_OUI_FROM_DATABASE=OCTAGON SYSTEMS CORP.
 
+OUI:FC9643*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
 OUI:FC9947*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -105482,6 +107372,9 @@ OUI:FCB662*
 OUI:FCB698*
  ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd.
 
+OUI:FCB69D*
+ ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd.
+
 OUI:FCB6D8*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -105527,6 +107420,51 @@ OUI:FCCAC4*
 OUI:FCCCE4*
  ID_OUI_FROM_DATABASE=Ascon Ltd.
 
+OUI:FCCD2F0*
+ ID_OUI_FROM_DATABASE=Ningbo Bull Digital Technology Co., LTD
+
+OUI:FCCD2F1*
+ ID_OUI_FROM_DATABASE=Siren Care(Shanghai) information and technology company
+
+OUI:FCCD2F2*
+ ID_OUI_FROM_DATABASE=Loupedeck Oy
+
+OUI:FCCD2F3*
+ ID_OUI_FROM_DATABASE=Xmitech Technology Co., Limited
+
+OUI:FCCD2F4*
+ ID_OUI_FROM_DATABASE=Genitek Engineering sprl
+
+OUI:FCCD2F5*
+ ID_OUI_FROM_DATABASE=QCTEK CO.,LTD.
+
+OUI:FCCD2F6*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
+OUI:FCCD2F7*
+ ID_OUI_FROM_DATABASE=Suzhou lehui display co.,ltd
+
+OUI:FCCD2F8*
+ ID_OUI_FROM_DATABASE=Asesorias y Servicios Innovaxxion SPA
+
+OUI:FCCD2F9*
+ ID_OUI_FROM_DATABASE=Aroma Retail
+
+OUI:FCCD2FA*
+ ID_OUI_FROM_DATABASE=SCOPUS INTERNATIONAL-BELGIUM
+
+OUI:FCCD2FB*
+ ID_OUI_FROM_DATABASE=HEAD-DIRECT (KUNSHAN) Co. Ltd
+
+OUI:FCCD2FC*
+ ID_OUI_FROM_DATABASE=Spedos ADS a.s.
+
+OUI:FCCD2FD*
+ ID_OUI_FROM_DATABASE=Shenzhen Smartbyte Technology Co., Ltd.
+
+OUI:FCCD2FE*
+ ID_OUI_FROM_DATABASE=Eltek brojila d.o.o.
+
 OUI:FCCF43*
  ID_OUI_FROM_DATABASE=HUIZHOU CITY HUIYANG DISTRICT MEISIQI INDUSTRY DEVELOPMENT CO,.LTD
 
@@ -105578,6 +107516,9 @@ OUI:FCD2B6D*
 OUI:FCD2B6E*
  ID_OUI_FROM_DATABASE=Univer S.p.A.
 
+OUI:FCD436*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
 OUI:FCD4F2*
  ID_OUI_FROM_DATABASE=The Coca Cola Company
 
index f6f948e35580e43790e526ed476e685325d18de3..f06de58509d2425ccdcd28eb47363d3954ec85f5 100644 (file)
@@ -177,6 +177,9 @@ acpi:LNRO*:
 acpi:LNUX*:
  ID_VENDOR_FROM_DATABASE=The Linux Foundation
 
+acpi:LOON*:
+ ID_VENDOR_FROM_DATABASE=Loongson Technology Corporation Limited
+
 acpi:MCHP*:
  ID_VENDOR_FROM_DATABASE=Microchip Technology Inc
 
@@ -222,6 +225,9 @@ acpi:PEGA*:
 acpi:PHYT*:
  ID_VENDOR_FROM_DATABASE=Phytium Technology Co. Ltd.
 
+acpi:PIXA*:
+ ID_VENDOR_FROM_DATABASE=PixArt imaging inc.
+
 acpi:QCOM*:
  ID_VENDOR_FROM_DATABASE=Qualcomm Inc
 
@@ -259,7 +265,7 @@ acpi:TCAG*:
  ID_VENDOR_FROM_DATABASE=Teracue AG
 
 acpi:TOSB*:
- ID_VENDOR_FROM_DATABASE=Toshiba Corporation
+ ID_VENDOR_FROM_DATABASE=Dynabook Inc.
 
 acpi:TXNW*:
  ID_VENDOR_FROM_DATABASE=Texas Instruments
@@ -1359,6 +1365,9 @@ acpi:CET*:
 acpi:CFG*:
  ID_VENDOR_FROM_DATABASE=Atlantis
 
+acpi:CFR*:
+ ID_VENDOR_FROM_DATABASE=Meta View, Inc.
+
 acpi:CGA*:
  ID_VENDOR_FROM_DATABASE=Chunghwa Picture Tubes, LTD
 
@@ -1485,6 +1494,9 @@ acpi:CMG*:
 acpi:CMI*:
  ID_VENDOR_FROM_DATABASE=C-Media Electronics
 
+acpi:CMK*:
+ ID_VENDOR_FROM_DATABASE=Comark LLC
+
 acpi:CMM*:
  ID_VENDOR_FROM_DATABASE=Comtime GmbH
 
@@ -4425,6 +4437,9 @@ acpi:MKT*:
 acpi:MKV*:
  ID_VENDOR_FROM_DATABASE=Trtheim Technology
 
+acpi:MLC*:
+ ID_VENDOR_FROM_DATABASE=MILCOTS
+
 acpi:MLD*:
  ID_VENDOR_FROM_DATABASE=Deep Video Imaging Ltd
 
@@ -4527,6 +4542,9 @@ acpi:MPN*:
 acpi:MPS*:
  ID_VENDOR_FROM_DATABASE=mps Software GmbH
 
+acpi:MPV*:
+ ID_VENDOR_FROM_DATABASE=Megapixel Visual Realty
+
 acpi:MPX*:
  ID_VENDOR_FROM_DATABASE=Micropix Technologies, Ltd.
 
@@ -4989,6 +5007,9 @@ acpi:NXQ*:
 acpi:NXS*:
  ID_VENDOR_FROM_DATABASE=Technology Nexus Secure Open Systems AB
 
+acpi:NXT*:
+ ID_VENDOR_FROM_DATABASE=NZXT (PNP same EDID)_
+
 acpi:NYC*:
  ID_VENDOR_FROM_DATABASE=Nakayo Relecommunications, Inc.
 
@@ -6150,6 +6171,9 @@ acpi:SKM*:
 acpi:SKT*:
  ID_VENDOR_FROM_DATABASE=Samsung Electro-Mechanics Company Ltd
 
+acpi:SKW*:
+ ID_VENDOR_FROM_DATABASE=Skyworth
+
 acpi:SKY*:
  ID_VENDOR_FROM_DATABASE=SKYDATA S.P.A.
 
@@ -6829,7 +6853,7 @@ acpi:TOP*:
  ID_VENDOR_FROM_DATABASE=Orion Communications Co., Ltd.
 
 acpi:TOS*:
- ID_VENDOR_FROM_DATABASE=Toshiba Corporation
+ ID_VENDOR_FROM_DATABASE=Dynabook Inc.
 
 acpi:TOU*:
  ID_VENDOR_FROM_DATABASE=Touchstone Technology
index c7a88660eab4d2737cc484b8e825b6d42be5af20..a3cfdf90ab943d75ff196c5f4ee83028575a483d 100644 (file)
@@ -1,5 +1,5 @@
---- 20-acpi-vendor.hwdb.base   2020-07-23 17:21:29.955652649 +0200
-+++ 20-acpi-vendor.hwdb        2020-07-23 17:21:29.974652774 +0200
+--- 20-acpi-vendor.hwdb.base   2020-10-13 09:40:27.449819401 +0200
++++ 20-acpi-vendor.hwdb        2020-10-13 09:40:27.464819680 +0200
 @@ -3,6 +3,8 @@
  # Data imported from:
  #     https://uefi.org/uefi-pnp-export
@@ -19,7 +19,7 @@
  acpi:AMDI*:
   ID_VENDOR_FROM_DATABASE=AMD
  
-@@ -289,6 +288,9 @@
+@@ -295,6 +294,9 @@
  acpi:AAA*:
   ID_VENDOR_FROM_DATABASE=Avolites Ltd
  
@@ -29,7 +29,7 @@
  acpi:AAE*:
   ID_VENDOR_FROM_DATABASE=Anatek Electronics Inc.
  
-@@ -316,6 +318,9 @@
+@@ -322,6 +324,9 @@
  acpi:ABO*:
   ID_VENDOR_FROM_DATABASE=D-Link Systems Inc
  
@@ -39,7 +39,7 @@
  acpi:ABS*:
   ID_VENDOR_FROM_DATABASE=Abaco Systems, Inc.
  
-@@ -361,7 +366,7 @@
+@@ -367,7 +372,7 @@
  acpi:ACO*:
   ID_VENDOR_FROM_DATABASE=Allion Computer Inc.
  
@@ -48,7 +48,7 @@
   ID_VENDOR_FROM_DATABASE=Aspen Tech Inc
  
  acpi:ACR*:
-@@ -634,6 +639,9 @@
+@@ -640,6 +645,9 @@
  acpi:AMT*:
   ID_VENDOR_FROM_DATABASE=AMT International Industry
  
@@ -58,7 +58,7 @@
  acpi:AMX*:
   ID_VENDOR_FROM_DATABASE=AMX LLC
  
-@@ -682,6 +690,9 @@
+@@ -688,6 +696,9 @@
  acpi:AOA*:
   ID_VENDOR_FROM_DATABASE=AOpen Inc.
  
@@ -68,7 +68,7 @@
  acpi:AOE*:
   ID_VENDOR_FROM_DATABASE=Advanced Optics Electronics, Inc.
  
-@@ -691,6 +702,9 @@
+@@ -697,6 +708,9 @@
  acpi:AOT*:
   ID_VENDOR_FROM_DATABASE=Alcatel
  
@@ -78,7 +78,7 @@
  acpi:APC*:
   ID_VENDOR_FROM_DATABASE=American Power Conversion
  
-@@ -866,7 +880,7 @@
+@@ -872,7 +886,7 @@
   ID_VENDOR_FROM_DATABASE=Alps Electric Inc
  
  acpi:AUO*:
@@ -87,7 +87,7 @@
  
  acpi:AUR*:
   ID_VENDOR_FROM_DATABASE=Aureal Semiconductor
-@@ -946,6 +960,9 @@
+@@ -952,6 +966,9 @@
  acpi:AXE*:
   ID_VENDOR_FROM_DATABASE=Axell Corporation
  
@@ -97,7 +97,7 @@
  acpi:AXI*:
   ID_VENDOR_FROM_DATABASE=American Magnetics
  
-@@ -1096,6 +1113,9 @@
+@@ -1102,6 +1119,9 @@
  acpi:BML*:
   ID_VENDOR_FROM_DATABASE=BIOMED Lab
  
  acpi:BMS*:
   ID_VENDOR_FROM_DATABASE=BIOMEDISYS
  
-@@ -1108,6 +1128,9 @@
+@@ -1114,6 +1134,9 @@
  acpi:BNO*:
   ID_VENDOR_FROM_DATABASE=Bang & Olufsen
  
  acpi:BNS*:
   ID_VENDOR_FROM_DATABASE=Boulder Nonlinear Systems
  
-@@ -1348,6 +1371,9 @@
+@@ -1357,6 +1380,9 @@
  acpi:CHA*:
   ID_VENDOR_FROM_DATABASE=Chase Research PLC
  
  acpi:CHD*:
   ID_VENDOR_FROM_DATABASE=ChangHong Electric Co.,Ltd
  
-@@ -1501,6 +1527,9 @@
+@@ -1513,6 +1539,9 @@
  acpi:COD*:
   ID_VENDOR_FROM_DATABASE=CODAN Pty. Ltd.
  
  acpi:COI*:
   ID_VENDOR_FROM_DATABASE=Codec Inc.
  
-@@ -1907,7 +1936,7 @@
+@@ -1919,7 +1948,7 @@
   ID_VENDOR_FROM_DATABASE=Dragon Information Technology
  
  acpi:DJE*:
  
  acpi:DJP*:
   ID_VENDOR_FROM_DATABASE=Maygay Machines, Ltd
-@@ -2239,6 +2268,9 @@
+@@ -2251,6 +2280,9 @@
  acpi:EIN*:
   ID_VENDOR_FROM_DATABASE=Elegant Invention
  
  acpi:EKA*:
   ID_VENDOR_FROM_DATABASE=MagTek Inc.
  
-@@ -2500,6 +2532,9 @@
+@@ -2512,6 +2544,9 @@
  acpi:FCG*:
   ID_VENDOR_FROM_DATABASE=First International Computer Ltd
  
  acpi:FCS*:
   ID_VENDOR_FROM_DATABASE=Focus Enhancements, Inc.
  
-@@ -2873,7 +2908,7 @@
+@@ -2885,7 +2920,7 @@
   ID_VENDOR_FROM_DATABASE=General Standards Corporation
  
  acpi:GSM*:
  
  acpi:GSN*:
   ID_VENDOR_FROM_DATABASE=Grandstream Networks, Inc.
-@@ -2974,6 +3009,9 @@
+@@ -2986,6 +3021,9 @@
  acpi:HEC*:
   ID_VENDOR_FROM_DATABASE=Hisense Electric Co., Ltd.
  
  acpi:HEL*:
   ID_VENDOR_FROM_DATABASE=Hitachi Micro Systems Europe Ltd
  
-@@ -3103,6 +3141,9 @@
+@@ -3115,6 +3153,9 @@
  acpi:HSD*:
   ID_VENDOR_FROM_DATABASE=HannStar Display Corp
  
  acpi:HSM*:
   ID_VENDOR_FROM_DATABASE=AT&T Microelectronics
  
-@@ -3226,6 +3267,9 @@
+@@ -3238,6 +3279,9 @@
  acpi:ICI*:
   ID_VENDOR_FROM_DATABASE=Infotek Communication Inc
  
  acpi:ICM*:
   ID_VENDOR_FROM_DATABASE=Intracom SA
  
-@@ -3322,6 +3366,9 @@
+@@ -3334,6 +3378,9 @@
  acpi:IKE*:
   ID_VENDOR_FROM_DATABASE=Ikegami Tsushinki Co. Ltd.
  
  acpi:IKS*:
   ID_VENDOR_FROM_DATABASE=Ikos Systems Inc
  
-@@ -3367,6 +3414,9 @@
+@@ -3379,6 +3426,9 @@
  acpi:IMT*:
   ID_VENDOR_FROM_DATABASE=Inmax Technology Corporation
  
  acpi:INA*:
   ID_VENDOR_FROM_DATABASE=Inventec Corporation
  
-@@ -3874,6 +3924,9 @@
+@@ -3886,6 +3936,9 @@
  acpi:LAN*:
   ID_VENDOR_FROM_DATABASE=Sodeman Lancom Inc
  
  acpi:LAS*:
   ID_VENDOR_FROM_DATABASE=LASAT Comm. A/S
  
-@@ -3919,6 +3972,9 @@
+@@ -3931,6 +3984,9 @@
  acpi:LED*:
   ID_VENDOR_FROM_DATABASE=Long Engineering Design Inc
  
  acpi:LEG*:
   ID_VENDOR_FROM_DATABASE=Legerity, Inc
  
-@@ -3934,6 +3990,9 @@
+@@ -3946,6 +4002,9 @@
  acpi:LGC*:
   ID_VENDOR_FROM_DATABASE=Logic Ltd
  
  acpi:LGI*:
   ID_VENDOR_FROM_DATABASE=Logitech Inc
  
-@@ -3988,6 +4047,9 @@
+@@ -4000,6 +4059,9 @@
  acpi:LND*:
   ID_VENDOR_FROM_DATABASE=Land Computer Company Ltd
  
  acpi:LNK*:
   ID_VENDOR_FROM_DATABASE=Link Tech Inc
  
-@@ -4022,7 +4084,7 @@
+@@ -4034,7 +4096,7 @@
   ID_VENDOR_FROM_DATABASE=Design Technology
  
  acpi:LPL*:
  
  acpi:LSC*:
   ID_VENDOR_FROM_DATABASE=LifeSize Communications
-@@ -4198,6 +4260,9 @@
+@@ -4210,6 +4272,9 @@
  acpi:MCX*:
   ID_VENDOR_FROM_DATABASE=Millson Custom Solutions Inc.
  
  acpi:MDA*:
   ID_VENDOR_FROM_DATABASE=Media4 Inc
  
-@@ -4435,6 +4500,9 @@
+@@ -4450,6 +4515,9 @@
  acpi:MOM*:
   ID_VENDOR_FROM_DATABASE=Momentum Data Systems
  
  acpi:MOS*:
   ID_VENDOR_FROM_DATABASE=Moses Corporation
  
-@@ -4660,6 +4728,9 @@
+@@ -4678,6 +4746,9 @@
  acpi:NAL*:
   ID_VENDOR_FROM_DATABASE=Network Alchemy
  
  acpi:NAT*:
   ID_VENDOR_FROM_DATABASE=NaturalPoint Inc.
  
-@@ -5164,6 +5235,9 @@
+@@ -5185,6 +5256,9 @@
  acpi:PCX*:
   ID_VENDOR_FROM_DATABASE=PC Xperten
  
  acpi:PDM*:
   ID_VENDOR_FROM_DATABASE=Psion Dacom Plc.
  
-@@ -5227,9 +5301,6 @@
+@@ -5248,9 +5322,6 @@
  acpi:PHE*:
   ID_VENDOR_FROM_DATABASE=Philips Medical Systems Boeblingen GmbH
  
  acpi:PHL*:
   ID_VENDOR_FROM_DATABASE=Philips Consumer Electronics Company
  
-@@ -5317,9 +5388,6 @@
+@@ -5338,9 +5409,6 @@
  acpi:PNL*:
   ID_VENDOR_FROM_DATABASE=Panelview, Inc.
  
  acpi:PNR*:
   ID_VENDOR_FROM_DATABASE=Planar Systems, Inc.
  
-@@ -5455,15 +5523,9 @@
+@@ -5476,15 +5544,9 @@
  acpi:PTS*:
   ID_VENDOR_FROM_DATABASE=Plain Tree Systems Inc
  
  acpi:PVG*:
   ID_VENDOR_FROM_DATABASE=Proview Global Co., Ltd
  
-@@ -5779,9 +5841,6 @@
+@@ -5800,9 +5862,6 @@
  acpi:RTI*:
   ID_VENDOR_FROM_DATABASE=Rancho Tech Inc
  
  acpi:RTL*:
   ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Company Ltd
  
-@@ -5947,9 +6006,6 @@
+@@ -5968,9 +6027,6 @@
  acpi:SEE*:
   ID_VENDOR_FROM_DATABASE=SeeColor Corporation
  
  acpi:SEI*:
   ID_VENDOR_FROM_DATABASE=Seitz & Associates Inc
  
-@@ -6406,6 +6462,9 @@
+@@ -6430,6 +6486,9 @@
  acpi:SVD*:
   ID_VENDOR_FROM_DATABASE=SVD Computer
  
  acpi:SVI*:
   ID_VENDOR_FROM_DATABASE=Sun Microsystems
  
-@@ -6490,6 +6549,9 @@
+@@ -6514,6 +6573,9 @@
  acpi:SZM*:
   ID_VENDOR_FROM_DATABASE=Shenzhen MTC Co., Ltd
  
  acpi:TAA*:
   ID_VENDOR_FROM_DATABASE=Tandberg
  
-@@ -6580,6 +6642,9 @@
+@@ -6604,6 +6666,9 @@
  acpi:TDG*:
   ID_VENDOR_FROM_DATABASE=Six15 Technologies
  
  acpi:TDM*:
   ID_VENDOR_FROM_DATABASE=Tandem Computer Europe Inc
  
-@@ -6622,6 +6687,9 @@
+@@ -6646,6 +6711,9 @@
  acpi:TEV*:
   ID_VENDOR_FROM_DATABASE=Televés, S.A.
  
  acpi:TEZ*:
   ID_VENDOR_FROM_DATABASE=Tech Source Inc.
  
-@@ -6736,9 +6804,6 @@
+@@ -6760,9 +6828,6 @@
  acpi:TNC*:
   ID_VENDOR_FROM_DATABASE=TNC Industrial Company Ltd
  
  acpi:TNM*:
   ID_VENDOR_FROM_DATABASE=TECNIMAGEN SA
  
-@@ -7045,14 +7110,14 @@
+@@ -7069,14 +7134,14 @@
  acpi:UNC*:
   ID_VENDOR_FROM_DATABASE=Unisys Corporation
  
  
  acpi:UNI*:
   ID_VENDOR_FROM_DATABASE=Uniform Industry Corp.
-@@ -7087,6 +7152,9 @@
+@@ -7111,6 +7176,9 @@
  acpi:USA*:
   ID_VENDOR_FROM_DATABASE=Utimaco Safeware AG
  
  acpi:USD*:
   ID_VENDOR_FROM_DATABASE=U.S. Digital Corporation
  
-@@ -7330,9 +7398,6 @@
+@@ -7354,9 +7422,6 @@
  acpi:WAL*:
   ID_VENDOR_FROM_DATABASE=Wave Access
  
  acpi:WAV*:
   ID_VENDOR_FROM_DATABASE=Wavephore
  
-@@ -7457,7 +7522,7 @@
+@@ -7481,7 +7546,7 @@
   ID_VENDOR_FROM_DATABASE=WyreStorm Technologies LLC
  
  acpi:WYS*:
  
  acpi:WYT*:
   ID_VENDOR_FROM_DATABASE=Wooyoung Image & Information Co.,Ltd.
-@@ -7471,9 +7536,6 @@
+@@ -7495,9 +7560,6 @@
  acpi:XDM*:
   ID_VENDOR_FROM_DATABASE=XDM Ltd.
  
  acpi:XES*:
   ID_VENDOR_FROM_DATABASE=Extreme Engineering Solutions, Inc.
  
-@@ -7504,9 +7566,6 @@
+@@ -7528,9 +7590,6 @@
  acpi:XNT*:
   ID_VENDOR_FROM_DATABASE=XN Technologies, Inc.
  
  acpi:XQU*:
   ID_VENDOR_FROM_DATABASE=SHANGHAI SVA-DAV ELECTRONICS CO., LTD
  
-@@ -7573,6 +7632,9 @@
+@@ -7597,6 +7656,9 @@
  acpi:ZBX*:
   ID_VENDOR_FROM_DATABASE=Zebax Technologies
  
index 4faf1336674fe41df55da7b28355953d5e220412..a98a50e95c4107d19511fd5836d4546a35774b9d 100644 (file)
@@ -11,6 +11,9 @@ pci:v*d*sv*sd*bc00sc00*
 pci:v*d*sv*sd*bc00sc01*
  ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible unclassified device
 
+pci:v*d*sv*sd*bc00sc05*
+ ID_PCI_SUBCLASS_FROM_DATABASE=Image coprocessor
+
 pci:v*d*sv*sd*bc01*
  ID_PCI_CLASS_FROM_DATABASE=Mass storage controller
 
index d2ab691b4f094557a9898feae7552c6f0e03cb86..a19490ed56af36116069ef128eb757950c60b17d 100644 (file)
@@ -1217,6 +1217,9 @@ pci:v00001000d0000005Dsv00001000sd00009364*
 pci:v00001000d0000005Dsv00001000sd0000936A*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] (MegaRAID SAS 9364-8i)
 
+pci:v00001000d0000005Dsv00001000sd00009380*
+ ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] (MegaRAID SAS 9380-8e)
+
 pci:v00001000d0000005Dsv00001028sd00001F41*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] (PERC H830 Adapter)
 
@@ -2139,7 +2142,7 @@ pci:v00001000d000000E6sv00001028sd0000200D*
  ID_MODEL_FROM_DATABASE=Fusion-MPT 12GSAS/PCIe Secure SAS38xx (HBA355e Adapter)
 
 pci:v00001000d000000E6sv00001028sd0000200E*
- ID_MODEL_FROM_DATABASE=Fusion-MPT 12GSAS/PCIe Secure SAS38xx (HBA355i MX)
+ ID_MODEL_FROM_DATABASE=Fusion-MPT 12GSAS/PCIe Secure SAS38xx (HBA350i MX)
 
 pci:v00001000d000000E6sv00001D49sd00000205*
  ID_MODEL_FROM_DATABASE=Fusion-MPT 12GSAS/PCIe Secure SAS38xx (ThinkSystem 440-16i SAS/SATA PCIe Gen4 12Gb Internal HBA)
@@ -2664,7 +2667,7 @@ pci:v00001002d00001479*
  ID_MODEL_FROM_DATABASE=Navi 10 XL Downstream Port of PCI Express Switch
 
 pci:v00001002d0000154C*
- ID_MODEL_FROM_DATABASE=Kryptos
+ ID_MODEL_FROM_DATABASE=Kryptos [Radeon RX 350]
 
 pci:v00001002d0000154E*
  ID_MODEL_FROM_DATABASE=Garfield
@@ -2748,13 +2751,13 @@ pci:v00001002d00003171*
  ID_MODEL_FROM_DATABASE=RV380 GL [FireMV 2400] (Secondary)
 
 pci:v00001002d00003E50*
- ID_MODEL_FROM_DATABASE=RV380 [Radeon X600]
+ ID_MODEL_FROM_DATABASE=RV380 [Radeon X550/X600]
 
 pci:v00001002d00003E54*
  ID_MODEL_FROM_DATABASE=RV380 GL [FireGL V3200]
 
 pci:v00001002d00003E70*
- ID_MODEL_FROM_DATABASE=RV380 [Radeon X600] (Secondary)
+ ID_MODEL_FROM_DATABASE=RV380 [Radeon X550/X600] (Secondary)
 
 pci:v00001002d00004136*
  ID_MODEL_FROM_DATABASE=RS100 [Mobility IGP 320M]
@@ -4449,43 +4452,43 @@ pci:v00001002d00005044sv00001002sd00000029*
  ID_MODEL_FROM_DATABASE=All-In-Wonder 128 PCI (Rage 128 AIW)
 
 pci:v00001002d00005046*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS]
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X]
 
 pci:v00001002d00005046sv00001002sd00000004*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury Pro)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury Pro)
 
 pci:v00001002d00005046sv00001002sd00000008*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury Pro/Xpert 2000 Pro)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury Pro/Xpert 2000 Pro)
 
 pci:v00001002d00005046sv00001002sd00000014*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury Pro)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury Pro)
 
 pci:v00001002d00005046sv00001002sd00000018*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury Pro/Xpert 2000 Pro)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury Pro/Xpert 2000 Pro)
 
 pci:v00001002d00005046sv00001002sd00000028*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage 128 Pro AIW AGP)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage 128 Pro AIW AGP)
 
 pci:v00001002d00005046sv00001002sd0000002A*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage 128 Pro AIW AGP)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage 128 Pro AIW AGP)
 
 pci:v00001002d00005046sv00001002sd00000048*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury Pro)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury Pro)
 
 pci:v00001002d00005046sv00001002sd00002000*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury MAXX AGP 4x (TMDS) (VGA device))
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury MAXX AGP 4x (TMDS) (VGA device))
 
 pci:v00001002d00005046sv00001002sd00002001*
- ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X TMDS] (Rage Fury MAXX AGP 4x (TMDS) (Extra device?!))
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X] (Rage Fury MAXX AGP 4x (TMDS) (Extra device?!))
 
 pci:v00001002d00005050*
- ID_MODEL_FROM_DATABASE=Rage128 [Xpert 128 PCI]
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO PCI / Xpert 128 PCI]
 
 pci:v00001002d00005050sv00001002sd00000008*
- ID_MODEL_FROM_DATABASE=Rage128 [Xpert 128 PCI] (Xpert 128)
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO PCI / Xpert 128 PCI] (Xpert 128)
 
 pci:v00001002d00005052*
- ID_MODEL_FROM_DATABASE=Rage 128 PRO AGP 4X TMDS
+ ID_MODEL_FROM_DATABASE=Rage 4 [Rage 128 PRO AGP 4X]
 
 pci:v00001002d00005144*
  ID_MODEL_FROM_DATABASE=R100 [Radeon 7200 / All-In-Wonder Radeon]
@@ -4778,12 +4781,6 @@ pci:v00001002d0000524Csv00001002sd00000008*
 pci:v00001002d0000524Csv00001002sd00000088*
  ID_MODEL_FROM_DATABASE=Rage 128 VR AGP (Xpert 99)
 
-pci:v00001002d00005346*
- ID_MODEL_FROM_DATABASE=Rage 128 SF/4x AGP 2x
-
-pci:v00001002d00005346sv00001002sd00000048*
- ID_MODEL_FROM_DATABASE=Rage 128 SF/4x AGP 2x (RAGE 128 16MB VGA TVOUT AMC PAL)
-
 pci:v00001002d0000534D*
  ID_MODEL_FROM_DATABASE=Rage 128 4X AGP 4x
 
@@ -4863,13 +4860,13 @@ pci:v00001002d0000554Bsv00001002sd00000302*
  ID_MODEL_FROM_DATABASE=R423 [Radeon X800 GT/SE] (Radeon X800 SE)
 
 pci:v00001002d0000554D*
- ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL]
+ ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO2/XL]
 
 pci:v00001002d0000554Dsv00001002sd00000322*
- ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] (All-In-Wonder X800 XL)
+ ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO2/XL] (All-In-Wonder X800 XL)
 
 pci:v00001002d0000554Dsv00001458sd00002124*
- ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] (GV-R80L256V-B (AGP))
+ ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO2/XL] (GV-R80L256V-B (AGP))
 
 pci:v00001002d0000554E*
  ID_MODEL_FROM_DATABASE=R430 [All-In-Wonder X800 GT]
@@ -4890,10 +4887,10 @@ pci:v00001002d0000556B*
  ID_MODEL_FROM_DATABASE=R423 [Radeon X800 GT] (Secondary)
 
 pci:v00001002d0000556D*
- ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] (Secondary)
+ ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO2/XL] (Secondary)
 
 pci:v00001002d0000556Dsv00001458sd00002125*
- ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] (Secondary) (GV-R80L256V-B (AGP))
+ ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO2/XL] (Secondary) (GV-R80L256V-B (AGP))
 
 pci:v00001002d0000556F*
  ID_MODEL_FROM_DATABASE=R430 [Radeon X800] (Secondary)
@@ -5043,10 +5040,10 @@ pci:v00001002d00005958*
  ID_MODEL_FROM_DATABASE=RD780 Host Bridge
 
 pci:v00001002d00005960*
- ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO]
+ ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO / 9250]
 
 pci:v00001002d00005960sv000017AFsd00002020*
- ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO] (Excalibur Radeon 9250)
+ ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO / 9250] (Excalibur Radeon 9250)
 
 pci:v00001002d00005961*
  ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200]
@@ -5547,25 +5544,25 @@ pci:v00001002d00006610sv00001642sd00003F09*
  ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon R7 350)
 
 pci:v00001002d00006611*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM]
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM]
 
 pci:v00001002d00006611sv00001028sd0000210B*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon R5 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R5 240 OEM)
 
 pci:v00001002d00006611sv00001642sd00001869*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon 520 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon 520 OEM)
 
 pci:v00001002d00006611sv0000174Bsd00004248*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
 
 pci:v00001002d00006611sv0000174Bsd0000A240*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
 
 pci:v00001002d00006611sv0000174Bsd0000D340*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon R7 340 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R7 340 OEM)
 
 pci:v00001002d00006611sv00001B0Asd000090D3*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R7 240 OEM)
 
 pci:v00001002d00006613*
  ID_MODEL_FROM_DATABASE=Oland PRO [Radeon R7 240/340]
@@ -7568,6 +7565,9 @@ pci:v00001002d000067CF*
 pci:v00001002d000067D0*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon Pro V7300X / V7350x2]
 
+pci:v00001002d000067D7*
+ ID_MODEL_FROM_DATABASE=Ellesmere [Radeon Pro WX 5100 / Barco MXRT-6700]
+
 pci:v00001002d000067DF*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]
 
@@ -7661,6 +7661,9 @@ pci:v00001002d000067DFsv00001682sd00009588*
 pci:v00001002d000067DFsv00001682sd0000C570*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570)
 
+pci:v00001002d000067DFsv00001682sd0000C580*
+ ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580)
+
 pci:v00001002d000067DFsv0000174Bsd0000E347*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 470/480)
 
@@ -7745,6 +7748,9 @@ pci:v00001002d000067EFsv00001028sd00001703*
 pci:v00001002d000067EFsv0000103Csd00003421*
  ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X] (Radeon RX 460)
 
+pci:v00001002d000067EFsv00001043sd00000561*
+ ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X] (AREZ Radeon RX 560)
+
 pci:v00001002d000067EFsv0000106Bsd00000160*
  ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X] (Radeon Pro 460)
 
@@ -8468,6 +8474,9 @@ pci:v00001002d0000687Fsv00001002sd00000B36*
 pci:v00001002d0000687Fsv00001002sd00006B76*
  ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (RX Vega64)
 
+pci:v00001002d0000687Fsv00001458sd0000230C*
+ ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (Radeon RX VEGA 56 GAMING OC 8G)
+
 pci:v00001002d00006880*
  ID_MODEL_FROM_DATABASE=Lexington [Radeon HD 6550M]
 
@@ -10010,6 +10019,9 @@ pci:v00001002d00006939sv0000148Csd00009380*
 pci:v00001002d00006939sv0000174Bsd0000E308*
  ID_MODEL_FROM_DATABASE=Tonga PRO [Radeon R9 285/380] (Radeon R9 380 Nitro 4G D5)
 
+pci:v00001002d0000693B*
+ ID_MODEL_FROM_DATABASE=Tonga PRO GL [FirePro W7100 / Barco MXRT-7600]
+
 pci:v00001002d0000694C*
  ID_MODEL_FROM_DATABASE=Polaris 22 XT [Radeon RX Vega M GH]
 
@@ -10083,10 +10095,10 @@ pci:v00001002d00007102*
  ID_MODEL_FROM_DATABASE=R520/M58 [Mobility Radeon X1800]
 
 pci:v00001002d00007104*
- ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200]
+ ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200 / Barco MXTR-5100]
 
 pci:v00001002d00007104sv000013CCsd00003D0A*
- ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200] (MXRT-5100)
+ ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200 / Barco MXTR-5100] (MXRT-5100)
 
 pci:v00001002d00007109*
  ID_MODEL_FROM_DATABASE=R520 [Radeon X1800 XL]
@@ -11150,6 +11162,9 @@ pci:v00001002d00009613*
 pci:v00001002d00009614*
  ID_MODEL_FROM_DATABASE=RS780D [Radeon HD 3300]
 
+pci:v00001002d00009615*
+ ID_MODEL_FROM_DATABASE=RS780E [Radeon HD 3200]
+
 pci:v00001002d00009616*
  ID_MODEL_FROM_DATABASE=RS780L [Radeon 3000]
 
@@ -11484,7 +11499,7 @@ pci:v00001002d00009919*
  ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7500G]
 
 pci:v00001002d0000991E*
- ID_MODEL_FROM_DATABASE=Bishop
+ ID_MODEL_FROM_DATABASE=Bishop [Xbox One S APU]
 
 pci:v00001002d00009920*
  ID_MODEL_FROM_DATABASE=Liverpool [Playstation 4 APU]
@@ -13592,6 +13607,12 @@ pci:v00001022d00001467*
 pci:v00001022d00001468*
  ID_MODEL_FROM_DATABASE=Zeppelin Cryptographic Coprocessor NTBCCP
 
+pci:v00001022d00001470*
+ ID_MODEL_FROM_DATABASE=Vega 10 PCIe Bridge
+
+pci:v00001022d00001471*
+ ID_MODEL_FROM_DATABASE=Vega 10 PCIe Bridge
+
 pci:v00001022d00001480*
  ID_MODEL_FROM_DATABASE=Starship/Matisse Root Complex
 
@@ -19839,58 +19860,58 @@ pci:v0000105Dd00002339sv0000105Dsd0000000B*
  ID_MODEL_FROM_DATABASE=Imagine 128-II (Imagine 128 series 2 8Mb H-VRAM)
 
 pci:v0000105Dd00002339sv000011A4sd0000000A*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000000*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000004*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000005*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000006*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000008*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd00000009*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd0000000A*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd00002339sv000013CCsd0000000C*
- ID_MODEL_FROM_DATABASE=Imagine 128-II (Barco Metheus 5 Megapixel)
+ ID_MODEL_FROM_DATABASE=Imagine 128-II (Metheus 5 Megapixel)
 
 pci:v0000105Dd0000493D*
  ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride]
 
 pci:v0000105Dd0000493Dsv000011A4sd0000000A*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000011A4sd0000000B*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd00000002*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 4 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 4 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd00000003*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd00000007*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd00000008*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd00000009*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd0000493Dsv000013CCsd0000000A*
- ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Barco Metheus 5 Megapixel, Dual Head)
+ ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] (Metheus 5 Megapixel, Dual Head)
 
 pci:v0000105Dd00005348*
  ID_MODEL_FROM_DATABASE=Revolution 4
@@ -27987,7 +28008,7 @@ pci:v000010DEd000000F4*
  ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 LE]
 
 pci:v000010DEd000000F5*
- ID_MODEL_FROM_DATABASE=G71 [GeForce 7800 GS]
+ ID_MODEL_FROM_DATABASE=G71 [GeForce 7800 GS AGP]
 
 pci:v000010DEd000000F6*
  ID_MODEL_FROM_DATABASE=NV43 [GeForce 6800 GS/XT]
@@ -29166,31 +29187,34 @@ pci:v000010DEd000002A6*
  ID_MODEL_FROM_DATABASE=MCPX Memory Controller
 
 pci:v000010DEd000002E0*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT]
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT AGP]
 
 pci:v000010DEd000002E0sv000002E0sd00002249*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT] (GF 7600GT 560M 256MB DDR3 DUAL DVI TV)
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT AGP] (GF 7600GT 560M 256MB DDR3 DUAL DVI TV)
 
 pci:v000010DEd000002E1*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS]
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS AGP]
 
 pci:v000010DEd000002E1sv00001682sd0000222B*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS] (PV-T73K-UAL3 (256MB))
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS AGP] (PV-T73K-UAL3 (256MB))
 
 pci:v000010DEd000002E1sv00001682sd00002247*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS] (GF 7600GS 512MB DDR2)
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS AGP] (GF 7600GS 512MB DDR2)
 
 pci:v000010DEd000002E2*
- ID_MODEL_FROM_DATABASE=G73 [GeForce 7300 GT]
+ ID_MODEL_FROM_DATABASE=G73 [GeForce 7300 GT AGP]
 
 pci:v000010DEd000002E3*
- ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GS]
+ ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GS AGP]
 
 pci:v000010DEd000002E4*
- ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT]
+ ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT AGP]
 
 pci:v000010DEd000002E4sv00001682sd00002271*
- ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT] (PV-T71A-YDF7 (512MB))
+ ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT AGP] (PV-T71A-YDF7 (512MB))
+
+pci:v000010DEd000002E5*
+ ID_MODEL_FROM_DATABASE=G71 [GeForce 7600 GS AGP]
 
 pci:v000010DEd000002F0*
  ID_MODEL_FROM_DATABASE=C51 Host Bridge
@@ -35526,10 +35550,10 @@ pci:v000010DEd00001E07sv00001462sd00003715*
  ID_MODEL_FROM_DATABASE=TU102 [GeForce RTX 2080 Ti Rev. A] (RTX 2080 Ti GAMING X TRIO)
 
 pci:v000010DEd00001E2D*
- ID_MODEL_FROM_DATABASE=TU102B
+ ID_MODEL_FROM_DATABASE=TU102 [GeForce RTX 2080 Ti Engineering Sample]
 
 pci:v000010DEd00001E2E*
- ID_MODEL_FROM_DATABASE=TU102B
+ ID_MODEL_FROM_DATABASE=TU102 [GeForce RTX 2080 Ti 12GB Engineering Sample]
 
 pci:v000010DEd00001E30*
  ID_MODEL_FROM_DATABASE=TU102GL [Quadro RTX 6000/8000]
@@ -35541,7 +35565,7 @@ pci:v000010DEd00001E30sv000010DEsd000012BA*
  ID_MODEL_FROM_DATABASE=TU102GL [Quadro RTX 6000/8000] (Quadro RTX 6000)
 
 pci:v000010DEd00001E36*
- ID_MODEL_FROM_DATABASE=TU102GL
+ ID_MODEL_FROM_DATABASE=TU102GL [Quadro RTX 6000]
 
 pci:v000010DEd00001E37*
  ID_MODEL_FROM_DATABASE=TU102GL [GRID RTX T10-4/T10-8/T10-16]
@@ -35708,6 +35732,9 @@ pci:v000010DEd00001F54*
 pci:v000010DEd00001F55*
  ID_MODEL_FROM_DATABASE=TU106BM [GeForce RTX 2060 Mobile]
 
+pci:v000010DEd00001F76*
+ ID_MODEL_FROM_DATABASE=TU106GLM [Quadro RTX 3000 Mobile Refresh]
+
 pci:v000010DEd00001F81*
  ID_MODEL_FROM_DATABASE=TU117
 
@@ -35732,9 +35759,15 @@ pci:v000010DEd00001F96*
 pci:v000010DEd00001F97*
  ID_MODEL_FROM_DATABASE=TU117M [GeForce MX450]
 
+pci:v000010DEd00001F98*
+ ID_MODEL_FROM_DATABASE=TU117M [GeForce MX450]
+
 pci:v000010DEd00001F99*
  ID_MODEL_FROM_DATABASE=TU117M
 
+pci:v000010DEd00001F9C*
+ ID_MODEL_FROM_DATABASE=TU117M [GeForce MX450]
+
 pci:v000010DEd00001FAE*
  ID_MODEL_FROM_DATABASE=TU117GL
 
@@ -35798,6 +35831,54 @@ pci:v000010DEd000021C4*
 pci:v000010DEd000021D1*
  ID_MODEL_FROM_DATABASE=TU116BM [GeForce GTX 1660 Ti Mobile]
 
+pci:v000010DEd00002204*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3090]
+
+pci:v000010DEd00002206*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 10GB / 20GB]
+
+pci:v000010DEd00002206sv000010DEsd0000146D*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 10GB / 20GB] (GA102 [GeForce RTX 3080 20GB])
+
+pci:v000010DEd00002206sv00001462sd00003892*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 10GB / 20GB] (RTX 3080 10GB GAMING X TRIO)
+
+pci:v000010DEd0000222B*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3090 Engineering Sample]
+
+pci:v000010DEd0000222F*
+ ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 11GB / 12GB Engineering Sample]
+
+pci:v000010DEd00002230*
+ ID_MODEL_FROM_DATABASE=GA102GL [RTX A6000]
+
+pci:v000010DEd0000223F*
+ ID_MODEL_FROM_DATABASE=GA102GL
+
+pci:v000010DEd00002482*
+ ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Ti]
+
+pci:v000010DEd00002484*
+ ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070]
+
+pci:v000010DEd00002486*
+ ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3060 Ti]
+
+pci:v000010DEd0000249C*
+ ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile]
+
+pci:v000010DEd0000249D*
+ ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile / Max-Q]
+
+pci:v000010DEd000024AF*
+ ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Engineering Sample]
+
+pci:v000010DEd000024BF*
+ ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Engineering Sample]
+
+pci:v000010DEd0000252F*
+ ID_MODEL_FROM_DATABASE=GA106 [GeForce RTX 3060 Engineering Sample]
+
 pci:v000010DF*
  ID_VENDOR_FROM_DATABASE=Emulex Corporation
 
@@ -36992,6 +37073,9 @@ pci:v000010ECd0000C821*
 pci:v000010ECd0000C822*
  ID_MODEL_FROM_DATABASE=RTL8822CE 802.11ac PCIe Wireless Network Adapter
 
+pci:v000010ECd0000C82F*
+ ID_MODEL_FROM_DATABASE=RTL8822CE 802.11ac PCIe Wireless Network Adapter
+
 pci:v000010ECd0000D723*
  ID_MODEL_FROM_DATABASE=RTL8723DE 802.11b/g/n PCIe Adapter
 
@@ -43037,6 +43121,36 @@ pci:v0000117Cd00000094sv0000117Csd000000A3*
 pci:v0000117Cd00000094sv0000117Csd000000AC*
  ID_MODEL_FROM_DATABASE=Celerity FC 16/32Gb/s Gen 6 Fibre Channel HBA (Celerity FC-324E)
 
+pci:v0000117Cd000000BB*
+ ID_MODEL_FROM_DATABASE=Celerity FC 32/64Gb/s Gen 7 Fibre Channel HBA
+
+pci:v0000117Cd000000BBsv0000117Csd000000BC*
+ ID_MODEL_FROM_DATABASE=Celerity FC 32/64Gb/s Gen 7 Fibre Channel HBA (Celerity FC-321P)
+
+pci:v0000117Cd000000BBsv0000117Csd000000BD*
+ ID_MODEL_FROM_DATABASE=Celerity FC 32/64Gb/s Gen 7 Fibre Channel HBA (Celerity FC-322P)
+
+pci:v0000117Cd000000BBsv0000117Csd000000BE*
+ ID_MODEL_FROM_DATABASE=Celerity FC 32/64Gb/s Gen 7 Fibre Channel HBA (Celerity FC-324P)
+
+pci:v0000117Cd000000E6*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA
+
+pci:v0000117Cd000000E6sv0000117Csd000000C0*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA (ExpressSAS H1280 GT)
+
+pci:v0000117Cd000000E6sv0000117Csd000000C1*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA (ExpressSAS H1208 GT)
+
+pci:v0000117Cd000000E6sv0000117Csd000000C2*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA (ExpressSAS H1244 GT)
+
+pci:v0000117Cd000000E6sv0000117Csd000000C3*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA (ExpressSAS H12F0 GT)
+
+pci:v0000117Cd000000E6sv0000117Csd000000C4*
+ ID_MODEL_FROM_DATABASE=ExpressSAS GT 12Gb/s SAS/SATA HBA (ExpressSAS H120F GT)
+
 pci:v0000117Cd00008013*
  ID_MODEL_FROM_DATABASE=ExpressPCI UL4D
 
@@ -43694,6 +43808,9 @@ pci:v0000118Dd00000324*
 pci:v0000118Dd00000344*
  ID_MODEL_FROM_DATABASE=Model 44 Road Runner Frame Grabber
 
+pci:v0000118Dd0000B04E*
+ ID_MODEL_FROM_DATABASE=Claxon CXP4 CoaXPress frame grabber
+
 pci:v0000118E*
  ID_VENDOR_FROM_DATABASE=Hermstedt GmbH
 
@@ -47018,6 +47135,9 @@ pci:v0000126Fd00000820*
 pci:v0000126Fd00000910*
  ID_MODEL_FROM_DATABASE=SM910
 
+pci:v0000126Fd00002262*
+ ID_MODEL_FROM_DATABASE=SM2262/SM2262EN SSD Controller
+
 pci:v00001270*
  ID_VENDOR_FROM_DATABASE=Olympus Optical Co., Ltd.
 
@@ -50562,7 +50682,7 @@ pci:v000013CB*
  ID_VENDOR_FROM_DATABASE=Yano Electric Co Ltd
 
 pci:v000013CC*
- ID_VENDOR_FROM_DATABASE=Metheus Corporation
+ ID_VENDOR_FROM_DATABASE=BARCO
 
 pci:v000013CD*
  ID_VENDOR_FROM_DATABASE=Compatible Systems Corporation
@@ -53888,6 +54008,9 @@ pci:v0000144D*
 pci:v0000144Dd00001600*
  ID_MODEL_FROM_DATABASE=Apple PCIe SSD
 
+pci:v0000144Dd0000A544*
+ ID_MODEL_FROM_DATABASE=Exynos 8890 PCIe Root Complex
+
 pci:v0000144Dd0000A800*
  ID_MODEL_FROM_DATABASE=XP941 PCIe SSD
 
@@ -54092,6 +54215,9 @@ pci:v0000144Dd0000A824sv00001028sd00002098*
 pci:v0000144Dd0000A824sv00001028sd00002099*
  ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 7.68TB)
 
+pci:v0000144Dd0000ECEC*
+ ID_MODEL_FROM_DATABASE=Exynos 8895 PCIe Root Complex
+
 pci:v0000144E*
  ID_VENDOR_FROM_DATABASE=OLITEC
 
@@ -56108,6 +56234,9 @@ pci:v000014E4d000016D6*
 pci:v000014E4d000016D6sv000014E4sd00004120*
  ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller (NetXtreme E-Series Advanced Dual-port 10Gb SFP+ Ethernet Network Daughter Card)
 
+pci:v000014E4d000016D6sv000014E4sd00004126*
+ ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller (NetXtreme-E Dual-port 10G SFP+ Ethernet OCP 3.0 Adapter (BCM957412N4120C))
+
 pci:v000014E4d000016D6sv0000152Dsd00008B20*
  ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller
 
@@ -56129,6 +56258,9 @@ pci:v000014E4d000016D7sv000014E4sd00001404*
 pci:v000014E4d000016D7sv000014E4sd00004140*
  ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller (NetXtreme E-Series Advanced Dual-port 25Gb SFP28 Network Daughter Card)
 
+pci:v000014E4d000016D7sv000014E4sd00004146*
+ ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller (NetXtreme-E Dual-port 25G SFP28 Ethernet OCP 3.0 Adapter (BCM957414N4140C))
+
 pci:v000014E4d000016D7sv00001590sd0000020E*
  ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller (Ethernet 25Gb 2-port 631SFP28 Adapter)
 
@@ -56142,7 +56274,10 @@ pci:v000014E4d000016D8sv00001028sd00001FEB*
  ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (NetXtreme-E 10Gb SFP+ Adapter)
 
 pci:v000014E4d000016D8sv000014E4sd00004163*
- ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (BCM957416M4163C OCP 2x10GBT Type1 wRoCE)
+ ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (NetXtreme-E Dual-port 10GBASE-T Ethernet OCP 2.0 Adapter (BCM957416M4163C))
+
+pci:v000014E4d000016D8sv000014E4sd00004166*
+ ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (NetXtreme-E Dual-port 10GBASE-T Ethernet OCP 3.0 Adapter (BCM957416N4160C))
 
 pci:v000014E4d000016D8sv00001590sd0000020C*
  ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (Ethernet 10Gb 2-port 535T Adapter)
@@ -56192,6 +56327,9 @@ pci:v000014E4d000016E8*
 pci:v000014E4d000016E9*
  ID_MODEL_FROM_DATABASE=BCM57407 NetXtreme-E 25Gb Ethernet Controller
 
+pci:v000014E4d000016EB*
+ ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E RDMA Partition
+
 pci:v000014E4d000016EC*
  ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E Ethernet Partition
 
@@ -56288,12 +56426,36 @@ pci:v000014E4d00001713sv000017AAsd00003A23*
 pci:v000014E4d00001750*
  ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet
 
+pci:v000014E4d00001750sv000014E4sd00002100*
+ ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (NetXtreme-E Dual-port 100G QSFP56 Ethernet PCIe4.0 x16 Adapter (BCM957508-P2100G))
+
+pci:v000014E4d00001750sv000014E4sd00005208*
+ ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (NetXtreme-E Dual-port 100G QSFP56 Ethernet OCP 3.0 Adapter (BCM957508-N2100G))
+
 pci:v000014E4d00001751*
  ID_MODEL_FROM_DATABASE=BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet
 
 pci:v000014E4d00001752*
  ID_MODEL_FROM_DATABASE=BCM57502 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet
 
+pci:v000014E4d00001800*
+ ID_MODEL_FROM_DATABASE=BCM57502 NetXtreme-E Ethernet Partition
+
+pci:v000014E4d00001801*
+ ID_MODEL_FROM_DATABASE=BCM57504 NetXtreme-E Ethernet Partition
+
+pci:v000014E4d00001802*
+ ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E Ethernet Partition
+
+pci:v000014E4d00001803*
+ ID_MODEL_FROM_DATABASE=BCM57502 NetXtreme-E RDMA Partition
+
+pci:v000014E4d00001804*
+ ID_MODEL_FROM_DATABASE=BCM57504 NetXtreme-E RDMA Partition
+
+pci:v000014E4d00001805*
+ ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E RDMA Partition
+
 pci:v000014E4d00001806*
  ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E Ethernet Virtual Function
 
@@ -56900,6 +57062,15 @@ pci:v000014E4d00004411*
 pci:v000014E4d00004412*
  ID_MODEL_FROM_DATABASE=BCM4412 10/100BaseT
 
+pci:v000014E4d0000441F*
+ ID_MODEL_FROM_DATABASE=BCM4361 802.11ac Dual-Band Wireless Network Controller
+
+pci:v000014E4d00004420*
+ ID_MODEL_FROM_DATABASE=BCM4361 802.11ac 2.4 GHz Wireless Network Controller
+
+pci:v000014E4d00004421*
+ ID_MODEL_FROM_DATABASE=BCM4361 802.11ac 5 GHz Wireless Network Controller
+
 pci:v000014E4d00004430*
  ID_MODEL_FROM_DATABASE=BCM44xx CardBus iLine32 HomePNA 2.0
 
@@ -58434,7 +58605,7 @@ pci:v00001528*
  ID_VENDOR_FROM_DATABASE=ACKSYS
 
 pci:v00001529*
- ID_VENDOR_FROM_DATABASE=AMERICAN MICROSystems Inc
+ ID_VENDOR_FROM_DATABASE=ON Semiconductor
 
 pci:v0000152A*
  ID_VENDOR_FROM_DATABASE=QUICKTURN DESIGN Systems
@@ -58634,9 +58805,24 @@ pci:v00001556d0000110F*
 pci:v00001556d00001110*
  ID_MODEL_FROM_DATABASE=XpressRich Reference Design
 
+pci:v00001556d00001111*
+ ID_MODEL_FROM_DATABASE=XpressRich-AXI Ref Design
+
+pci:v00001556d00001112*
+ ID_MODEL_FROM_DATABASE=QuickPCIe
+
 pci:v00001556d00001113*
  ID_MODEL_FROM_DATABASE=XpressSwitch
 
+pci:v00001556d00001114*
+ ID_MODEL_FROM_DATABASE=Inspector
+
+pci:v00001556d00001115*
+ ID_MODEL_FROM_DATABASE=XpressLINK Ref Design
+
+pci:v00001556d00001116*
+ ID_MODEL_FROM_DATABASE=XpressLINK-SOC Ref Design
+
 pci:v00001556d0000BE00*
  ID_MODEL_FROM_DATABASE=PCI Express Bridge
 
@@ -59405,9 +59591,6 @@ pci:v000015B3d00001017sv000015B3sd00000020*
 pci:v000015B3d00001017sv000015B3sd00000068*
  ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5] (ConnectX®-5 EN network interface card for OCP2.0, Type 1, with host management, 25GbE dual-port SFP28, PCIe3.0 x8, no bracket Halogen free ; MCX542B-ACAN)
 
-pci:v000015B3d00001017sv000015B3sd00000125*
- ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5] (Tencent ConnectX-5 EN Ex network interface card for OCP 3.0, with host management, 50GbE Dual-port QSFP28, PCIe4.0 x16, Thumbscrew (pull-tab) bracket)
-
 pci:v000015B3d00001018*
  ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5 Virtual Function]
 
@@ -59417,6 +59600,9 @@ pci:v000015B3d00001019*
 pci:v000015B3d00001019sv000015B3sd00000008*
  ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5 Ex] (ConnectX-5 Ex EN network interface card, 100GbE dual-port QSFP28, PCIe4.0 x16, tall bracket; MCX516A-CDAT)
 
+pci:v000015B3d00001019sv000015B3sd00000125*
+ ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5 Ex] (Tencent ConnectX-5 EN Ex network interface card for OCP 3.0, with host management, 50GbE Dual-port QSFP28, PCIe4.0 x16, Thumbscrew (pull-tab) bracket)
+
 pci:v000015B3d0000101A*
  ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5 Ex Virtual Function]
 
@@ -61361,6 +61547,9 @@ pci:v0000168Cd00000042*
 pci:v0000168Cd00000042sv000011ADsd000008A6*
  ID_MODEL_FROM_DATABASE=QCA9377 802.11ac Wireless Network Adapter (Qualcomm Atheros QCA9377 802.11ac Wireless Network Adapter)
 
+pci:v0000168Cd00000042sv000017AAsd00000901*
+ ID_MODEL_FROM_DATABASE=QCA9377 802.11ac Wireless Network Adapter (Qualcomm Atheros QCA9377 Wireless Network Adapter)
+
 pci:v0000168Cd00000046*
  ID_MODEL_FROM_DATABASE=QCA9984 802.11ac Wave 2 Wireless Network Adapter
 
@@ -62036,6 +62225,36 @@ pci:v00001760d00000143*
 pci:v00001760d00000144*
  ID_MODEL_FROM_DATABASE=PCA7408AS - Analog Inputs/Outputs
 
+pci:v00001760d00000145*
+ ID_MODEL_FROM_DATABASE=PCA-7228AL Multifunction PCI IO card
+
+pci:v00001760d00000146*
+ ID_MODEL_FROM_DATABASE=PCA-7228AS Multifunction PCI IO card
+
+pci:v00001760d00000147*
+ ID_MODEL_FROM_DATABASE=PCA7428AL Multifunction PCI IO card
+
+pci:v00001760d00000148*
+ ID_MODEL_FROM_DATABASE=PCA7428AS Multifunction PCI IO card
+
+pci:v00001760d00000149*
+ ID_MODEL_FROM_DATABASE=PCA7228EL Multifunction PCI IO card with isolated analog inputs
+
+pci:v00001760d00000150*
+ ID_MODEL_FROM_DATABASE=PCA7428EL Multifunction PCI IO card with isolated analog inputs
+
+pci:v00001760d00000151*
+ ID_MODEL_FROM_DATABASE=PCA7628AL - PCI card with analog inputs, counters and DIO
+
+pci:v00001760d00000152*
+ ID_MODEL_FROM_DATABASE=PCA7628AS PCI card with analog inputs, outputs, counters and DIO
+
+pci:v00001760d00000161*
+ ID_MODEL_FROM_DATABASE=PCA7288A PCI card with analog outputs, counters and DIO
+
+pci:v00001760d00000180*
+ ID_MODEL_FROM_DATABASE=PCI1052 Communication card for MicroUnit network
+
 pci:v00001760d00000214*
  ID_MODEL_FROM_DATABASE=PCT-7424C (F0) PC card with standard counters
 
@@ -62576,6 +62795,9 @@ pci:v000017A0d00008084*
 pci:v000017A0d00009750*
  ID_MODEL_FROM_DATABASE=GL9750 SD Host Controller
 
+pci:v000017A0d0000E763*
+ ID_MODEL_FROM_DATABASE=GL9763E eMMC Controller
+
 pci:v000017AA*
  ID_VENDOR_FROM_DATABASE=Lenovo
 
@@ -62639,12 +62861,30 @@ pci:v000017CBd00000002sv00001385sd00006D00*
 pci:v000017CBd00000002sv00001737sd00000054*
  ID_MODEL_FROM_DATABASE=AGN300 802.11 a/b/g True MIMO Wireless Card (WPC54GX4 v1 802.11g Wireless-G Notebook Adapter with SRX400)
 
+pci:v000017CBd00000105*
+ ID_MODEL_FROM_DATABASE=MSM8998 PCIe Root Complex
+
+pci:v000017CBd00000108*
+ ID_MODEL_FROM_DATABASE=SM8150/SA8195P PCIe Root Complex
+
+pci:v000017CBd00000300*
+ ID_MODEL_FROM_DATABASE=MDM9x35 LTE Modem
+
+pci:v000017CBd00000301*
+ ID_MODEL_FROM_DATABASE=MDM9640 PCIe Root Complex
+
+pci:v000017CBd00000302*
+ ID_MODEL_FROM_DATABASE=MDM9x55 LTE Modem [Snapdragon X12]
+
 pci:v000017CBd00000400*
  ID_MODEL_FROM_DATABASE=Datacenter Technologies QDF2432 PCI Express Root Port
 
 pci:v000017CBd00000401*
  ID_MODEL_FROM_DATABASE=Datacenter Technologies QDF2400 PCI Express Root Port
 
+pci:v000017CBd00001000*
+ ID_MODEL_FROM_DATABASE=QCS405 PCIe Root Complex
+
 pci:v000017CC*
  ID_VENDOR_FROM_DATABASE=NetChip Technology, Inc
 
@@ -64812,7 +65052,7 @@ pci:v00001957d000000B6*
  ID_MODEL_FROM_DATABASE=MPC8314E
 
 pci:v00001957d000000B6sv00001A56sd00001101*
- ID_MODEL_FROM_DATABASE=MPC8314E (Killer Xeno Pro Gigabit Ethernet Controller)
+ ID_MODEL_FROM_DATABASE=MPC8314E (Bigfoot Killer Xeno Pro Gigabit Ethernet Controller)
 
 pci:v00001957d000000C2*
  ID_MODEL_FROM_DATABASE=MPC8379E
@@ -64929,7 +65169,7 @@ pci:v00001957d0000C006*
  ID_MODEL_FROM_DATABASE=MPC8308
 
 pci:v00001957d0000C006sv00001A56sd00001201*
- ID_MODEL_FROM_DATABASE=MPC8308 (Killer E2100 Gigabit Ethernet Controller)
+ ID_MODEL_FROM_DATABASE=MPC8308 (Bigfoot Killer E2100 Gigabit Ethernet Controller)
 
 pci:v00001957d0000FC02*
  ID_MODEL_FROM_DATABASE=RedStone
@@ -64994,6 +65234,21 @@ pci:v00001966d00001975*
 pci:v00001966d00001977*
  ID_MODEL_FROM_DATABASE=DVG128 family
 
+pci:v00001966d00001979*
+ ID_MODEL_FROM_DATABASE=3DVG/UHD3
+
+pci:v00001966d00001980*
+ ID_MODEL_FROM_DATABASE=HDV2/UHD2
+
+pci:v00001966d00001980sv00001234sd00003160*
+ ID_MODEL_FROM_DATABASE=HDV2/UHD2 (UHD2LC)
+
+pci:v00001966d00001980sv00001234sd00003300*
+ ID_MODEL_FROM_DATABASE=HDV2/UHD2 (Legacy UHD2)
+
+pci:v00001966d00001980sv00001234sd00003410*
+ ID_MODEL_FROM_DATABASE=HDV2/UHD2 (UHD2)
+
 pci:v00001969*
  ID_VENDOR_FROM_DATABASE=Qualcomm Atheros
 
@@ -65735,6 +65990,9 @@ pci:v00001A08*
 pci:v00001A08d00000000*
  ID_MODEL_FROM_DATABASE=SC15064
 
+pci:v00001A0D*
+ ID_VENDOR_FROM_DATABASE=SEAKR Engineering
+
 pci:v00001A0E*
  ID_VENDOR_FROM_DATABASE=DekTec Digital Video B.V.
 
@@ -65913,7 +66171,7 @@ pci:v00001A55d00000090*
  ID_MODEL_FROM_DATABASE=CinePlay
 
 pci:v00001A56*
- ID_VENDOR_FROM_DATABASE=Bigfoot Networks, Inc.
+ ID_VENDOR_FROM_DATABASE=Rivet Networks
 
 pci:v00001A57*
  ID_VENDOR_FROM_DATABASE=Highly Reliable Systems
@@ -66083,6 +66341,9 @@ pci:v00001AE0*
 pci:v00001AE0d00000042*
  ID_MODEL_FROM_DATABASE=Compute Engine Virtual Ethernet [gVNIC]
 
+pci:v00001AE0d0000ABCD*
+ ID_MODEL_FROM_DATABASE=Airbrush Combined Paintbox IPU/Oscar Edge TPU [Pixel Neural Core]
+
 pci:v00001AE3*
  ID_VENDOR_FROM_DATABASE=SANBlaze Technology, Inc.
 
@@ -66095,17 +66356,83 @@ pci:v00001AE7d00000520*
 pci:v00001AE8*
  ID_VENDOR_FROM_DATABASE=Silicon Software GmbH
 
+pci:v00001AE8d00000751*
+ ID_MODEL_FROM_DATABASE=mE5 marathon VCL
+
+pci:v00001AE8d00000752*
+ ID_MODEL_FROM_DATABASE=mE5 marathon AF2
+
+pci:v00001AE8d00000753*
+ ID_MODEL_FROM_DATABASE=mE5 marathon ACX QP
+
+pci:v00001AE8d00000754*
+ ID_MODEL_FROM_DATABASE=mE5 marathon ACL
+
+pci:v00001AE8d00000755*
+ ID_MODEL_FROM_DATABASE=mE5 marathon ACX SP
+
+pci:v00001AE8d00000756*
+ ID_MODEL_FROM_DATABASE=mE5 marathon ACX DP
+
+pci:v00001AE8d00000757*
+ ID_MODEL_FROM_DATABASE=mE5 marathon VCX QP
+
+pci:v00001AE8d00000758*
+ ID_MODEL_FROM_DATABASE=mE5 marathon VF2
+
+pci:v00001AE8d00000759*
+ ID_MODEL_FROM_DATABASE=mE5 marathon VCLx
+
 pci:v00001AE8d00000A40*
- ID_MODEL_FROM_DATABASE=microEnable IV-BASE x1
+ ID_MODEL_FROM_DATABASE=microEnable IV AD1-CL
 
 pci:v00001AE8d00000A41*
- ID_MODEL_FROM_DATABASE=microEnable IV-FULL x1
+ ID_MODEL_FROM_DATABASE=microEnable IV VD1-CL
+
+pci:v00001AE8d00000A42*
+ ID_MODEL_FROM_DATABASE=microEnable IV AD4-CL
 
 pci:v00001AE8d00000A44*
- ID_MODEL_FROM_DATABASE=microEnable IV-FULL x4
+ ID_MODEL_FROM_DATABASE=microEnable IV VD4-CL
+
+pci:v00001AE8d00000A45*
+ ID_MODEL_FROM_DATABASE=microEnable IV AS1-CL
+
+pci:v00001AE8d00000A53*
+ ID_MODEL_FROM_DATABASE=microEnable 5 AQ8-CXP6B
+
+pci:v00001AE8d00000A54*
+ ID_MODEL_FROM_DATABASE=microEnable 5 VQ8-CXP6B
+
+pci:v00001AE8d00000A56*
+ ID_MODEL_FROM_DATABASE=microEnable 5 VQ8-CXP6D
+
+pci:v00001AE8d00000A57*
+ ID_MODEL_FROM_DATABASE=microEnable 5 AQ8-CXP6D
+
+pci:v00001AE8d00000A58*
+ ID_MODEL_FROM_DATABASE=microEnable 5 VD8-CL
+
+pci:v00001AE8d00000A5A*
+ ID_MODEL_FROM_DATABASE=microEnable 5 AD8-CL
+
+pci:v00001AE8d00000B52*
+ ID_MODEL_FROM_DATABASE=mE5 Abacus 4G Base
+
+pci:v00001AE8d00000B53*
+ ID_MODEL_FROM_DATABASE=mE5 Abacus 4G Base II
+
+pci:v00001AE8d00000B61*
+ ID_MODEL_FROM_DATABASE=mE6 Abacus 4TG
+
+pci:v00001AE8d00000B63*
+ ID_MODEL_FROM_DATABASE=CXP-12 Interface Card 1C
+
+pci:v00001AE8d00000E42*
+ ID_MODEL_FROM_DATABASE=microEnable IV AQ4-GE
 
 pci:v00001AE8d00000E44*
- ID_MODEL_FROM_DATABASE=microEnable IV-GigE x4
+ ID_MODEL_FROM_DATABASE=microEnable IV VQ4-GE
 
 pci:v00001AE9*
  ID_VENDOR_FROM_DATABASE=Wilocity Ltd.
@@ -66302,6 +66629,9 @@ pci:v00001B21d00000612sv00001849sd00000612*
 pci:v00001B21d00001042*
  ID_MODEL_FROM_DATABASE=ASM1042 SuperSpeed USB Host Controller
 
+pci:v00001B21d00001042sv00001043sd00001059*
+ ID_MODEL_FROM_DATABASE=ASM1042 SuperSpeed USB Host Controller (K53SM motherboard)
+
 pci:v00001B21d00001042sv00001043sd00008488*
  ID_MODEL_FROM_DATABASE=ASM1042 SuperSpeed USB Host Controller (P8B WS Motherboard)
 
@@ -66332,6 +66662,9 @@ pci:v00001B21d00001343*
 pci:v00001B21d00002142*
  ID_MODEL_FROM_DATABASE=ASM2142 USB 3.1 Host Controller
 
+pci:v00001B21d00003242*
+ ID_MODEL_FROM_DATABASE=ASM3242 USB 3.2 Host Controller
+
 pci:v00001B26*
  ID_VENDOR_FROM_DATABASE=Netcope Technologies, a.s.
 
@@ -66521,6 +66854,15 @@ pci:v00001B4B*
 pci:v00001B4Bd00000640*
  ID_MODEL_FROM_DATABASE=88SE9128 SATA III 6Gb/s RAID Controller
 
+pci:v00001B4Bd00002241*
+ ID_MODEL_FROM_DATABASE=88NR2241 Non-Volatile memory controller
+
+pci:v00001B4Bd00002241sv00001D49sd00000306*
+ ID_MODEL_FROM_DATABASE=88NR2241 Non-Volatile memory controller (ThinkSystem M.2 NVMe 2-Bay RAID Enablement Kit)
+
+pci:v00001B4Bd00002241sv00001D49sd00000307*
+ ID_MODEL_FROM_DATABASE=88NR2241 Non-Volatile memory controller (ThinkSystem 7mm NVMe 2-Bay Rear RAID Enablement Kit)
+
 pci:v00001B4Bd00009120*
  ID_MODEL_FROM_DATABASE=88SE9120 SATA 6Gb/s Controller
 
@@ -66584,6 +66926,21 @@ pci:v00001B4Bd00009230sv00001028sd00002010*
 pci:v00001B4Bd00009230sv00001D49sd00000300*
  ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem M.2 with Mirroring Enablement Kit)
 
+pci:v00001B4Bd00009230sv00001D49sd00000301*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SR630 x16 PCIE with 4 SATA ports Riser)
+
+pci:v00001B4Bd00009230sv00001D49sd00000302*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit)
+
+pci:v00001B4Bd00009230sv00001D49sd00000303*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit)
+
+pci:v00001B4Bd00009230sv00001D49sd00000304*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem M.2 SATA 2-Bay RAID Enablement Kit)
+
+pci:v00001B4Bd00009230sv00001D49sd00000305*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem 7mm SATA 2-Bay Rear RAID Enablement Kit)
+
 pci:v00001B4Bd00009235*
  ID_MODEL_FROM_DATABASE=88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller
 
@@ -66596,6 +66953,9 @@ pci:v00001B4Bd00009480*
 pci:v00001B4Bd00009485*
  ID_MODEL_FROM_DATABASE=88SE9485 SAS/SATA 6Gb/s controller
 
+pci:v00001B4C*
+ ID_VENDOR_FROM_DATABASE=GALAX
+
 pci:v00001B55*
  ID_VENDOR_FROM_DATABASE=NetUP Inc.
 
@@ -67154,6 +67514,12 @@ pci:v00001C5Cd00001327*
 pci:v00001C5Cd00001504*
  ID_MODEL_FROM_DATABASE=SC300 512GB M.2 2280 SATA Solid State Drive
 
+pci:v00001C5Cd00002839*
+ ID_MODEL_FROM_DATABASE=PE8000 Series NVMe Solid State Drive
+
+pci:v00001C5Cd00002839sv00000100sd00001C5C*
+ ID_MODEL_FROM_DATABASE=PE8000 Series NVMe Solid State Drive
+
 pci:v00001C5F*
  ID_VENDOR_FROM_DATABASE=Beijing Memblaze Technology Co. Ltd.
 
@@ -67214,23 +67580,35 @@ pci:v00001CB0*
 pci:v00001CB0d0000D000*
  ID_MODEL_FROM_DATABASE=Venice NVMe SSD
 
+pci:v00001CB0d0000D000sv00001CB0sd00002010*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series OCS U.2)
+
+pci:v00001CB0d0000D000sv00001CB0sd00002011*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice Series OCS U.2)
+
+pci:v00001CB0d0000D000sv00001CB0sd00002012*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series OCS U.2)
+
 pci:v00001CB0d0000D000sv00001CB0sd00002F10*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series U.2 SSD)
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series NVMe U.2)
 
 pci:v00001CB0d0000D000sv00001CB0sd00002F11*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice Series U.2 SSD)
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice Series NVMe U.2)
 
 pci:v00001CB0d0000D000sv00001CB0sd00002F12*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series U.2 SSD)
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series NVMe U.2)
 
-pci:v00001CB0d0000D000sv00001CB0sd0000AF10*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series AIC SSD)
+pci:v00001CB0d0000D000sv00001CB0sd0000A010*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series OCS AIC)
 
-pci:v00001CB0d0000D000sv00001CB0sd0000AF11*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice Series AIC SSD)
+pci:v00001CB0d0000D000sv00001CB0sd0000A012*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series OCS AIC)
+
+pci:v00001CB0d0000D000sv00001CB0sd0000AF10*
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-E Series NVMe AIC)
 
 pci:v00001CB0d0000D000sv00001CB0sd0000AF12*
- ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series AIC SSD)
+ ID_MODEL_FROM_DATABASE=Venice NVMe SSD (Venice-X Series NVMe AIC)
 
 pci:v00001CB1*
  ID_VENDOR_FROM_DATABASE=Collion UG & Co.KG
@@ -67778,42 +68156,42 @@ pci:v00001D78*
 pci:v00001D78d00001512*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller
 
-pci:v00001D78d00001512sv00001D78sd00002003*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 1.6TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002004*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 HHHL 2TB NVMe SSD)
 
-pci:v00001D78d00001512sv00001D78sd00002005*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 3.2TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002006*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 HHHL 4TB NVMe SSD)
 
-pci:v00001D78d00001512sv00001D78sd00002007*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 6.4TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002008*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 HHHL 8TB NVMe SSD)
 
-pci:v00001D78d00001512sv00001D78sd00002103*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 1.6TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002104*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 U.2 2TB NVMe SSD)
 
-pci:v00001D78d00001512sv00001D78sd00002105*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 3.2TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002106*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 U.2 4TB NVMe SSD)
 
-pci:v00001D78d00001512sv00001D78sd00002107*
- ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 6.4TB NVMe SSD)
-
 pci:v00001D78d00001512sv00001D78sd00002108*
  ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5437 U.2 8TB NVMe SSD)
 
+pci:v00001D78d00001512sv00001D78sd00003003*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 1.6TB NVMe SSD)
+
+pci:v00001D78d00001512sv00001D78sd00003005*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 3.2TB NVMe SSD)
+
+pci:v00001D78d00001512sv00001D78sd00003007*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 HHHL 6.4TB NVMe SSD)
+
+pci:v00001D78d00001512sv00001D78sd00003103*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 1.6TB NVMe SSD)
+
+pci:v00001D78d00001512sv00001D78sd00003105*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 3.2TB NVMe SSD)
+
+pci:v00001D78d00001512sv00001D78sd00003107*
+ ID_MODEL_FROM_DATABASE=TAI NVMe Controller (D5457 U.2 6.4TB NVMe SSD)
+
 pci:v00001D7C*
  ID_VENDOR_FROM_DATABASE=Aerotech, Inc.
 
@@ -67989,7 +68367,7 @@ pci:v00001DCD*
  ID_VENDOR_FROM_DATABASE=Liqid Inc.
 
 pci:v00001DD8*
- ID_VENDOR_FROM_DATABASE=Pensando Systems Inc
+ ID_VENDOR_FROM_DATABASE=Pensando Systems
 
 pci:v00001DD8d00001000*
  ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port
@@ -68003,9 +68381,21 @@ pci:v00001DD8d00001000sv00001DD8sd00004001*
 pci:v00001DD8d00001000sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001000sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001000sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001000sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001000sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001000sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DD8d00001001*
  ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port
 
@@ -68018,9 +68408,21 @@ pci:v00001DD8d00001001sv00001DD8sd00004001*
 pci:v00001DD8d00001001sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001001sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001001sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001001sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001001sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001001sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DD8d00001002*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller
 
@@ -68033,9 +68435,21 @@ pci:v00001DD8d00001002sv00001DD8sd00004001*
 pci:v00001DD8d00001002sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001002sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001002sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001002sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001002sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001002sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DD8d00001003*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF
 
@@ -68048,9 +68462,21 @@ pci:v00001DD8d00001003sv00001DD8sd00004001*
 pci:v00001DD8d00001003sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001003sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001003sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001003sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001003sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001003sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DD8d00001004*
  ID_MODEL_FROM_DATABASE=DSC Management Controller
 
@@ -68063,9 +68489,21 @@ pci:v00001DD8d00001004sv00001DD8sd00004001*
 pci:v00001DD8d00001004sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Management Controller (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001004sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001004sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001004sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001004sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001004sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DD8d00001007*
  ID_MODEL_FROM_DATABASE=DSC Storage Accelerator
 
@@ -68078,9 +68516,21 @@ pci:v00001DD8d00001007sv00001DD8sd00004001*
 pci:v00001DD8d00001007sv00001DD8sd00004002*
  ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (Naples 25Gb 2-port SFP28 x8 4GB)
 
+pci:v00001DD8d00001007sv00001DD8sd00004007*
+ ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-25 10/25G 2p OCP Card)
+
 pci:v00001DD8d00001007sv00001DD8sd00004008*
  ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC)
 
+pci:v00001DD8d00001007sv00001DD8sd0000400A*
+ ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card)
+
+pci:v00001DD8d00001007sv00001DD8sd0000400C*
+ ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card)
+
+pci:v00001DD8d00001007sv00001DD8sd0000400D*
+ ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-100 100G 2p QSFP28 Card)
+
 pci:v00001DE0*
  ID_VENDOR_FROM_DATABASE=Groq
 
@@ -68111,6 +68561,9 @@ pci:v00001DE5d00001000*
 pci:v00001DE5d00002000*
  ID_MODEL_FROM_DATABASE=NoLoad Hardware Development Kit
 
+pci:v00001DE5d00003000*
+ ID_MODEL_FROM_DATABASE=eBPF-based PCIe Accelerator
+
 pci:v00001DEE*
  ID_VENDOR_FROM_DATABASE=Biwin Storage Technology Co., Ltd.
 
@@ -68192,6 +68645,24 @@ pci:v00001DF3d00000204sv00001DF3sd00000001*
 pci:v00001DF3d00000204sv00001DF3sd00000002*
  ID_MODEL_FROM_DATABASE=ACE-NIC-NID Programmable Network Accelerator (ENA1020ZS)
 
+pci:v00001DF3d00000205*
+ ID_MODEL_FROM_DATABASE=ACE-NIC250 Programmable Network Accelerator
+
+pci:v00001DF3d00000205sv00001DF3sd00000000*
+ ID_MODEL_FROM_DATABASE=ACE-NIC250 Programmable Network Accelerator (Maintenance Mode)
+
+pci:v00001DF3d00000205sv00001DF3sd00000001*
+ ID_MODEL_FROM_DATABASE=ACE-NIC250 Programmable Network Accelerator (ENA2250F)
+
+pci:v00001DF3d00000206*
+ ID_MODEL_FROM_DATABASE=ACE-NIC200 Programmable Network Accelerator
+
+pci:v00001DF3d00000206sv00001DF3sd00000000*
+ ID_MODEL_FROM_DATABASE=ACE-NIC200 Programmable Network Accelerator (Maintenance Mode)
+
+pci:v00001DF3d00000206sv00001DF3sd00000001*
+ ID_MODEL_FROM_DATABASE=ACE-NIC200 Programmable Network Accelerator (ENA2200F)
+
 pci:v00001DF7*
  ID_VENDOR_FROM_DATABASE=opencpi.org
 
@@ -68216,6 +68687,66 @@ pci:v00001E0F*
 pci:v00001E0Fd00000007*
  ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6
 
+pci:v00001E0Fd00000007sv00001028sd00002078*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (DC NVMe CD6 RI 960GB)
+
+pci:v00001E0Fd00000007sv00001028sd00002079*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (DC NVMe CD6 RI 1.92TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000207A*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (DC NVMe CD6 RI 3.84TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000207B*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (DC NVMe CD6 RI 7.68TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000207C*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (DC NVMe CD6 RI 15.36TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000207E*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 RI 1.92TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000207F*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 RI 3.84TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002080*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 RI 7.68TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002081*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 RI 15.36TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002084*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 MU 1.6TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002085*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 MU 3.2TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002086*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe CM6 MU 6.4TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210A*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 RI 1.92TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210B*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 RI 3.84TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210C*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 RI 7.68TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210D*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 RI15.36TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210E*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 MU 1.6TB)
+
+pci:v00001E0Fd00000007sv00001028sd0000210F*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 MU 3.2TB)
+
+pci:v00001E0Fd00000007sv00001028sd00002110*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Dell Ent NVMe FIPS CM6 MU 6.4TB)
+
+pci:v00001E0Fd00000007sv00001E0Fsd00000001*
+ ID_MODEL_FROM_DATABASE=NVMe SSD Controller Cx6 (Generic NVMe CM6 RI 3.84TB)
+
 pci:v00001E17*
  ID_VENDOR_FROM_DATABASE=Arnold & Richter Cine Technik GmbH & Co. Betriebs KG
 
@@ -68255,6 +68786,9 @@ pci:v00001E36d00000001*
 pci:v00001E38*
  ID_VENDOR_FROM_DATABASE=Blaize, Inc
 
+pci:v00001E38d00000102*
+ ID_MODEL_FROM_DATABASE=Xplorer X1600
+
 pci:v00001E3D*
  ID_VENDOR_FROM_DATABASE=Burlywood, Inc
 
@@ -68303,6 +68837,12 @@ pci:v00001E57d00000100sv00000000sd00000100*
 pci:v00001E6B*
  ID_VENDOR_FROM_DATABASE=Axiado Corp.
 
+pci:v00001E7C*
+ ID_VENDOR_FROM_DATABASE=Brainchip Inc
+
+pci:v00001E7Cd0000BCA1*
+ ID_MODEL_FROM_DATABASE=AKD1000 Neural Network Coprocessor [Akida]
+
 pci:v00001E85*
  ID_VENDOR_FROM_DATABASE=Heitec AG
 
@@ -68321,6 +68861,12 @@ pci:v00001E94*
 pci:v00001E95*
  ID_VENDOR_FROM_DATABASE=Solid State Storage Technology Corporation
 
+pci:v00001EB1*
+ ID_VENDOR_FROM_DATABASE=VeriSilicon Inc
+
+pci:v00001EB1d00001001*
+ ID_MODEL_FROM_DATABASE=Video Accelerator
+
 pci:v00001FC0*
  ID_VENDOR_FROM_DATABASE=Ascom (Finland) Oy
 
@@ -68558,6 +69104,9 @@ pci:v00002348d00002010*
 pci:v00002646*
  ID_VENDOR_FROM_DATABASE=Kingston Technology Company, Inc.
 
+pci:v00002646d00002263*
+ ID_MODEL_FROM_DATABASE=A2000, M.2, 500GB
+
 pci:v0000270B*
  ID_VENDOR_FROM_DATABASE=Xantel Corporation
 
@@ -68694,7 +69243,7 @@ pci:v00003442d00001922*
  ID_MODEL_FROM_DATABASE=AS-i 3.0 PCI Master
 
 pci:v00003475*
- ID_VENDOR_FROM_DATABASE=Arastra Inc.
+ ID_VENDOR_FROM_DATABASE=Arista Networks, Inc.
 
 pci:v00003513*
  ID_VENDOR_FROM_DATABASE=ARCOM Control Systems Ltd
@@ -68852,6 +69401,9 @@ pci:v00003D3Dd000007A1*
 pci:v00003D3Dd000007A2*
  ID_MODEL_FROM_DATABASE=Sun XVR-500 Graphics Accelerator
 
+pci:v00003D3Dd000007A2sv00003D3Dsd00001047*
+ ID_MODEL_FROM_DATABASE=Sun XVR-500 Graphics Accelerator (Sun XVR-600 Graphics Accelerator)
+
 pci:v00003D3Dd000007A3*
  ID_MODEL_FROM_DATABASE=Wildcat IV 7210
 
@@ -71018,12 +71570,21 @@ pci:v00008086d00000172*
 pci:v00008086d00000176*
  ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller
 
+pci:v00008086d00000284*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP LPC Premium Controller/eSPI Controller
+
+pci:v00008086d000002A3*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP SMBus Host Controller
+
 pci:v00008086d000002A4*
  ID_MODEL_FROM_DATABASE=Comet Lake SPI (flash) Controller
 
 pci:v00008086d000002A6*
  ID_MODEL_FROM_DATABASE=Comet Lake North Peak
 
+pci:v00008086d000002C8*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP cAVS
+
 pci:v00008086d000002D3*
  ID_MODEL_FROM_DATABASE=Comet Lake SATA AHCI Controller
 
@@ -71036,11 +71597,26 @@ pci:v00008086d000002E8*
 pci:v00008086d000002E9*
  ID_MODEL_FROM_DATABASE=Comet Lake Serial IO I2C Host Controller
 
+pci:v00008086d000002ED*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP USB 3.1 xHCI Host Controller
+
+pci:v00008086d000002EF*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP Shared SRAM
+
 pci:v00008086d000002F0*
- ID_MODEL_FROM_DATABASE=Wireless-AC 9462
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP CNVi WiFi
+
+pci:v00008086d000002F0sv00008086sd00000034*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP CNVi WiFi (Wireless-AC 9560 160MHz)
 
 pci:v00008086d000002F0sv00008086sd00000070*
- ID_MODEL_FROM_DATABASE=Wireless-AC 9462 (Intel(R) Wi-Fi 6 AX201 160MHz)
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP CNVi WiFi (Wi-Fi 6 AX201 160MHz)
+
+pci:v00008086d000002F0sv00008086sd00000074*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP CNVi WiFi (Wi-Fi 6 AX201 160MHz)
+
+pci:v00008086d000002F5*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP SCS3
 
 pci:v00008086d000002F9*
  ID_MODEL_FROM_DATABASE=Comet Lake Thermal Subsytem
@@ -71135,6 +71711,9 @@ pci:v00008086d0000040A*
 pci:v00008086d00000412*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller
 
+pci:v00008086d00000412sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (EliteDesk 800 G1)
+
 pci:v00008086d00000412sv000017AAsd0000309F*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (ThinkCentre M83)
 
@@ -71325,7 +71904,16 @@ pci:v00008086d000006EF*
  ID_MODEL_FROM_DATABASE=Comet Lake PCH Shared SRAM
 
 pci:v00008086d000006F0*
- ID_MODEL_FROM_DATABASE=Wi-Fi 6 AX201
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH CNVi WiFi
+
+pci:v00008086d000006F0sv00008086sd00000034*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH CNVi WiFi (Wireless-AC 9560)
+
+pci:v00008086d000006F0sv00008086sd00000074*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH CNVi WiFi (Wi-Fi 6 AX201 160MHz)
+
+pci:v00008086d000006F0sv00008086sd000002A4*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH CNVi WiFi (Wireless-AC 9462)
 
 pci:v00008086d000006F9*
  ID_MODEL_FROM_DATABASE=Comet Lake PCH Thermal Controller
@@ -72291,7 +72879,7 @@ pci:v00008086d00000A54sv00001D49sd00004812*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (Thinksystem U.2 P4610 NVMe SSD)
 
 pci:v00008086d00000A54sv00008086sd00004308*
- ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (Intel SSD D5-P4320 and D5-P4326)
+ ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (SSD D5-P4320 and D5-P4326)
 
 pci:v00008086d00000A54sv00008086sd00004702*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (NVMe Datacenter SSD [3DNAND] SE 2.5" U.2 (P4500))
@@ -72458,6 +73046,9 @@ pci:v00008086d00000BF7*
 pci:v00008086d00000C00*
  ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller
 
+pci:v00008086d00000C00sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (EliteDesk 800 G1)
+
 pci:v00008086d00000C00sv000017AAsd0000309F*
  ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (ThinkCentre M83)
 
@@ -72485,6 +73076,9 @@ pci:v00008086d00000C09*
 pci:v00008086d00000C0C*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller
 
+pci:v00008086d00000C0Csv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller (EliteDesk 800 G1)
+
 pci:v00008086d00000C0Csv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller (ThinkPad T440p)
 
@@ -75965,6 +76559,9 @@ pci:v00008086d0000153A*
 pci:v00008086d0000153Asv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=Ethernet Connection I217-LM (ZBook 15)
 
+pci:v00008086d0000153Asv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=Ethernet Connection I217-LM (EliteDesk 800 G1)
+
 pci:v00008086d0000153Asv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=Ethernet Connection I217-LM (ThinkPad T440p)
 
@@ -76589,6 +77186,9 @@ pci:v00008086d00001592sv00008086sd0000000A*
 pci:v00008086d00001592sv00008086sd0000000B*
  ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet 100G 2P E810-C Adapter)
 
+pci:v00008086d00001592sv00008086sd0000000C*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet 100G 2P E810-C OCP)
+
 pci:v00008086d00001593*
  ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for SFP
 
@@ -76806,7 +77406,7 @@ pci:v00008086d000015D5*
  ID_MODEL_FROM_DATABASE=Ethernet SDI Adapter FM10420-25GbE-DA2
 
 pci:v00008086d000015D5sv00008086sd00000001*
- ID_MODEL_FROM_DATABASE=Ethernet SDI Adapter FM10420-25GbE-DA2 (Intel(R) Ethernet SDI Adapter FM10420-25GbE-DA2)
+ ID_MODEL_FROM_DATABASE=Ethernet SDI Adapter FM10420-25GbE-DA2
 
 pci:v00008086d000015D6*
  ID_MODEL_FROM_DATABASE=Ethernet Connection (5) I219-V
@@ -76881,10 +77481,16 @@ pci:v00008086d000015F0*
  ID_MODEL_FROM_DATABASE=JHL7540 Thunderbolt 3 USB Controller [Titan Ridge DD 2018]
 
 pci:v00008086d000015F2*
- ID_MODEL_FROM_DATABASE=Intel(R) Ethernet Controller I225-LM
+ ID_MODEL_FROM_DATABASE=Ethernet Controller I225-LM
+
+pci:v00008086d000015F2sv00008086sd00000001*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller I225-LM (Ethernet Network Adapter I225-T1)
+
+pci:v00008086d000015F2sv00008086sd00000002*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller I225-LM (Ethernet Network Adapter I225-T1)
 
 pci:v00008086d000015F3*
- ID_MODEL_FROM_DATABASE=Intel(R) Ethernet Controller I225-V
+ ID_MODEL_FROM_DATABASE=Ethernet Controller I225-V
 
 pci:v00008086d000015F4*
  ID_MODEL_FROM_DATABASE=Ethernet Connection (15) I219-LM
@@ -77088,7 +77694,7 @@ pci:v00008086d00001900*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
 
 pci:v00008086d00001901*
- ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x16)
+ ID_MODEL_FROM_DATABASE=6th-9th Gen Core Processor PCIe Controller (x16)
 
 pci:v00008086d00001902*
  ID_MODEL_FROM_DATABASE=HD Graphics 510
@@ -83891,9 +84497,6 @@ pci:v00008086d000027E2*
 pci:v00008086d000027E2sv00001775sd000011CC*
  ID_MODEL_FROM_DATABASE=82801GR/GH/GHM (ICH7 Family) PCI Express Port 6 (CC11/CL11)
 
-pci:v00008086d0000280B*
- ID_MODEL_FROM_DATABASE=Intel(R) Display Audio
-
 pci:v00008086d00002810*
  ID_MODEL_FROM_DATABASE=82801HB/HR (ICH8/R) LPC Interface Controller
 
@@ -87116,6 +87719,9 @@ pci:v00008086d00002FFD*
 pci:v00008086d00002FFE*
  ID_MODEL_FROM_DATABASE=Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers
 
+pci:v00008086d00003140*
+ ID_MODEL_FROM_DATABASE=Easel/Monette Hill Image Processor [Pixel Visual Core]
+
 pci:v00008086d00003165*
  ID_MODEL_FROM_DATABASE=Wireless 3165
 
@@ -87143,6 +87749,9 @@ pci:v00008086d0000318C*
 pci:v00008086d0000318E*
  ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor NorthPeak
 
+pci:v00008086d00003190*
+ ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Gaussian Mixture Model
+
 pci:v00008086d00003192*
  ID_MODEL_FROM_DATABASE=Gemini Lake P2SB
 
@@ -87209,6 +87818,9 @@ pci:v00008086d000031DA*
 pci:v00008086d000031DB*
  ID_MODEL_FROM_DATABASE=Gemini Lake PCI Express Root Port
 
+pci:v00008086d000031DC*
+ ID_MODEL_FROM_DATABASE=AC 1550i Wireless
+
 pci:v00008086d000031EE*
  ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Serial IO UART Host Controller
 
@@ -88082,6 +88694,12 @@ pci:v00008086d0000373F*
 pci:v00008086d000037C8*
  ID_MODEL_FROM_DATABASE=C62x Chipset QuickAssist Technology
 
+pci:v00008086d000037C8sv00008086sd00000001*
+ ID_MODEL_FROM_DATABASE=C62x Chipset QuickAssist Technology (QuickAssist Adapter 8960)
+
+pci:v00008086d000037C8sv00008086sd00000002*
+ ID_MODEL_FROM_DATABASE=C62x Chipset QuickAssist Technology (QuickAssist Adapter 8970)
+
 pci:v00008086d000037CC*
  ID_MODEL_FROM_DATABASE=Ethernet Connection X722
 
@@ -89316,7 +89934,7 @@ pci:v00008086d00003E1Fsv00001458sd00005000*
  ID_MODEL_FROM_DATABASE=8th Gen Core 4-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S] (Z370 AORUS Gaming K3-CF)
 
 pci:v00008086d00003E30*
- ID_MODEL_FROM_DATABASE=8th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
+ ID_MODEL_FROM_DATABASE=8th/9th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
 
 pci:v00008086d00003E33*
  ID_MODEL_FROM_DATABASE=8th/9th Gen Core Processor Host Bridge/DRAM Registers [Coffee Lake]
@@ -91209,7 +91827,7 @@ pci:v00008086d00008A23*
  ID_MODEL_FROM_DATABASE=Ice Lake Thunderbolt 3 PCI Express Root Port #3
 
 pci:v00008086d00008A51*
- ID_MODEL_FROM_DATABASE=Intel Iris Plus Graphics G7 (Ice Lake)
+ ID_MODEL_FROM_DATABASE=Iris Plus Graphics G7 (Ice Lake)
 
 pci:v00008086d00008A52*
  ID_MODEL_FROM_DATABASE=Iris Plus Graphics G7
@@ -91221,7 +91839,7 @@ pci:v00008086d00008A5A*
  ID_MODEL_FROM_DATABASE=Iris Plus Graphics G4 (Ice Lake)
 
 pci:v00008086d00008A5C*
- ID_MODEL_FROM_DATABASE=Intel Iris Plus Graphics G4 (Ice Lake)
+ ID_MODEL_FROM_DATABASE=Iris Plus Graphics G4 (Ice Lake)
 
 pci:v00008086d00008C00*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode]
@@ -91232,6 +91850,9 @@ pci:v00008086d00008C01*
 pci:v00008086d00008C02*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]
 
+pci:v00008086d00008C02sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (EliteDesk 800 G1)
+
 pci:v00008086d00008C02sv000017AAsd0000309F*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (ThinkCentre M83)
 
@@ -91271,6 +91892,9 @@ pci:v00008086d00008C0F*
 pci:v00008086d00008C10*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1
 
+pci:v00008086d00008C10sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 (EliteDesk 800 G1)
+
 pci:v00008086d00008C10sv00001043sd00008534*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 (ASUS H81I-PLUS)
 
@@ -91283,6 +91907,9 @@ pci:v00008086d00008C11*
 pci:v00008086d00008C12*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #2
 
+pci:v00008086d00008C12sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #2 (EliteDesk 800 G1)
+
 pci:v00008086d00008C12sv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #2 (ThinkPad T440p)
 
@@ -91331,6 +91958,9 @@ pci:v00008086d00008C20*
 pci:v00008086d00008C20sv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller (ZBook 15)
 
+pci:v00008086d00008C20sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller (EliteDesk 800 G1)
+
 pci:v00008086d00008C20sv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller (ThinkPad T440p)
 
@@ -91346,6 +91976,9 @@ pci:v00008086d00008C22*
 pci:v00008086d00008C22sv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ZBook 15)
 
+pci:v00008086d00008C22sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (EliteDesk 800 G1)
+
 pci:v00008086d00008C22sv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ThinkPad T440p)
 
@@ -91364,6 +91997,9 @@ pci:v00008086d00008C26*
 pci:v00008086d00008C26sv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ZBook 15)
 
+pci:v00008086d00008C26sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (EliteDesk 800 G1)
+
 pci:v00008086d00008C26sv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ThinkPad T440p)
 
@@ -91382,6 +92018,9 @@ pci:v00008086d00008C2D*
 pci:v00008086d00008C2Dsv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ZBook 15)
 
+pci:v00008086d00008C2Dsv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (EliteDesk 800 G1)
+
 pci:v00008086d00008C2Dsv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ThinkPad T440p)
 
@@ -91394,6 +92033,9 @@ pci:v00008086d00008C31*
 pci:v00008086d00008C31sv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ZBook 15)
 
+pci:v00008086d00008C31sv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (EliteDesk 800 G1)
+
 pci:v00008086d00008C31sv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ThinkPad T440p)
 
@@ -91412,6 +92054,9 @@ pci:v00008086d00008C3A*
 pci:v00008086d00008C3Asv0000103Csd00001909*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ZBook 15)
 
+pci:v00008086d00008C3Asv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (EliteDesk 800 G1)
+
 pci:v00008086d00008C3Asv000017AAsd0000220E*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ThinkPad T440p)
 
@@ -91427,6 +92072,9 @@ pci:v00008086d00008C3C*
 pci:v00008086d00008C3D*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family KT Controller
 
+pci:v00008086d00008C3Dsv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family KT Controller (EliteDesk 800 G1)
+
 pci:v00008086d00008C40*
  ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller
 
@@ -91475,6 +92123,9 @@ pci:v00008086d00008C4D*
 pci:v00008086d00008C4E*
  ID_MODEL_FROM_DATABASE=Q87 Express LPC Controller
 
+pci:v00008086d00008C4Esv0000103Csd00001998*
+ ID_MODEL_FROM_DATABASE=Q87 Express LPC Controller (EliteDesk 800 G1)
+
 pci:v00008086d00008C4F*
  ID_MODEL_FROM_DATABASE=QM87 Express LPC Controller
 
@@ -91922,12 +92573,18 @@ pci:v00008086d00009B44*
 pci:v00008086d00009B54*
  ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers
 
+pci:v00008086d00009B61*
+ ID_MODEL_FROM_DATABASE=Comet Lake-U v1 4c Host Bridge/DRAM Controller
+
 pci:v00008086d00009B64*
  ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers
 
 pci:v00008086d00009BC4*
  ID_MODEL_FROM_DATABASE=UHD Graphics
 
+pci:v00008086d00009BC8*
+ ID_MODEL_FROM_DATABASE=UHD Graphics 630
+
 pci:v00008086d00009C00*
  ID_MODEL_FROM_DATABASE=8 Series SATA Controller 1 [IDE mode]
 
@@ -93677,6 +94334,15 @@ pci:v00008086d0000A379*
 pci:v00008086d0000A379sv00001028sd00000869*
  ID_MODEL_FROM_DATABASE=Cannon Lake PCH Thermal Controller (Vostro 3470)
 
+pci:v00008086d0000A382*
+ ID_MODEL_FROM_DATABASE=400 Series Chipset Family SATA AHCI Controller
+
+pci:v00008086d0000A3A3*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-V SMBus Host Controller
+
+pci:v00008086d0000A3B1*
+ ID_MODEL_FROM_DATABASE=Comet Lake PCH-V Thermal Subsystem
+
 pci:v00008086d0000A620*
  ID_MODEL_FROM_DATABASE=6400/6402 Advanced Memory Buffer (AMB)
 
@@ -93795,7 +94461,7 @@ pci:v00008086d0000F1A6*
  ID_MODEL_FROM_DATABASE=SSD Pro 7600p/760p/E 6100p Series
 
 pci:v00008086d0000F1A6sv00008086sd0000390B*
- ID_MODEL_FROM_DATABASE=SSD Pro 7600p/760p/E 6100p Series (Intel Corporation SSD Pro 7600p/760p/E 6100p Series [NVM Express])
+ ID_MODEL_FROM_DATABASE=SSD Pro 7600p/760p/E 6100p Series ([NVM Express])
 
 pci:v00008086d0000F1A8*
  ID_MODEL_FROM_DATABASE=SSD 660P Series
@@ -94839,217 +95505,217 @@ pci:v00009005d0000028Dsv00009005sd00000554*
  ID_MODEL_FROM_DATABASE=Series 8 12G SAS/PCIe 3 (Series 8 - ASR-8885 - 8 internal 8 external 12G SAS Port/PCIe 3.0)
 
 pci:v00009005d0000028F*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS
 
 pci:v00009005d0000028Fsv0000103Csd00000600*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P408i-p SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P408i-p SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000601*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P408e-p SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P408e-p SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000602*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P408i-a SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P408i-a SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000603*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P408i-c SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P408i-c SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000650*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array E208i-p SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array E208i-p SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000651*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array E208e-p SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array E208e-p SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000652*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array E208i-c SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array E208i-c SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000654*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array E208i-a SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array E208i-a SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000655*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P408e-m SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P408e-m SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000700*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P204i-c SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P204i-c SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00000701*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P204i-b SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P204i-b SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00001100*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P816i-a SR Gen10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P816i-a SR Gen10)
 
 pci:v00009005d0000028Fsv0000103Csd00001101*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P416ie-m SR G10)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (Smart Array P416ie-m SR G10)
 
 pci:v00009005d0000028Fsv0000105Bsd00001211*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 8238-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 8238-16i)
 
 pci:v00009005d0000028Fsv0000105Bsd00001321*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 8242-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 8242-24i)
 
 pci:v00009005d0000028Fsv000013FEsd00008312*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SKY-9200 MIC-8312BridgeB)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SKY-9200 MIC-8312BridgeB)
 
 pci:v00009005d0000028Fsv0000152Dsd00008A22*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8204-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (QS-8204-8i)
 
 pci:v00009005d0000028Fsv0000152Dsd00008A23*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8238-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (QS-8238-16i)
 
 pci:v00009005d0000028Fsv0000152Dsd00008A24*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8236-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (QS-8236-16i)
 
 pci:v00009005d0000028Fsv0000152Dsd00008A36*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8240-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (QS-8240-24i)
 
 pci:v00009005d0000028Fsv0000152Dsd00008A37*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8242-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (QS-8242-24i)
 
 pci:v00009005d0000028Fsv0000193Dsd00008460*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA H460-M1)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA H460-M1)
 
 pci:v00009005d0000028Fsv0000193Dsd00008461*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA H460-B1)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA H460-B1)
 
 pci:v00009005d0000028Fsv0000193Dsd0000C460*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-M2)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID P460-M2)
 
 pci:v00009005d0000028Fsv0000193Dsd0000C461*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-B2)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID P460-B2)
 
 pci:v00009005d0000028Fsv0000193Dsd0000F460*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-M4)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID P460-M4)
 
 pci:v00009005d0000028Fsv0000193Dsd0000F461*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-B4)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID P460-B4)
 
 pci:v00009005d0000028Fsv000019E5sd0000D227*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC-HD SR465C-M 4G)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartROC-HD SR465C-M 4G)
 
 pci:v00009005d0000028Fsv000019E5sd0000D228*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC SR455C-M 2G)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartROC SR455C-M 2G)
 
 pci:v00009005d0000028Fsv000019E5sd0000D229*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartIOC SR155-M)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartIOC SR155-M)
 
 pci:v00009005d0000028Fsv000019E5sd0000D22A*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartIOC-HD SR765-M)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartIOC-HD SR765-M)
 
 pci:v00009005d0000028Fsv000019E5sd0000D22B*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC-e SR455C-ME 4G)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartROC-e SR455C-ME 4G)
 
 pci:v00009005d0000028Fsv000019E5sd0000D22C*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC SR455C-M 4G)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartROC SR455C-M 4G)
 
 pci:v00009005d0000028Fsv00001BD4sd00000045*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SMART-HBA 8242-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SMART-HBA 8242-24i)
 
 pci:v00009005d0000028Fsv00001BD4sd00000046*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID 8236-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID 8236-16i)
 
 pci:v00009005d0000028Fsv00001BD4sd00000047*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID 8240-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID 8240-24i)
 
 pci:v00009005d0000028Fsv00001BD4sd00000048*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SMART-HBA 8238-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SMART-HBA 8238-16i)
 
 pci:v00009005d0000028Fsv00001BD4sd0000004A*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (PM8222-SHBA)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (PM8222-SHBA)
 
 pci:v00009005d0000028Fsv00001BD4sd0000004B*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID PM8204-2GB)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID PM8204-2GB)
 
 pci:v00009005d0000028Fsv00001BD4sd0000004C*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID PM8204-4GB)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (RAID PM8204-4GB)
 
 pci:v00009005d0000028Fsv00001BD4sd0000004F*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (PM8222-HBA)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (PM8222-HBA)
 
 pci:v00009005d0000028Fsv00009005sd00000608*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3162-8i /e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3162-8i /e)
 
 pci:v00009005d0000028Fsv00009005sd00000800*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000801*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3152-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3152-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000802*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3151-4i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3151-4i)
 
 pci:v00009005d0000028Fsv00009005sd00000803*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3101-4i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3101-4i)
 
 pci:v00009005d0000028Fsv00009005sd00000804*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-8e)
 
 pci:v00009005d0000028Fsv00009005sd00000805*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3102-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3102-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000806*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3100)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3100)
 
 pci:v00009005d0000028Fsv00009005sd00000807*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3162-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3162-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000900*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000901*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-4i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-4i)
 
 pci:v00009005d0000028Fsv00009005sd00000902*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-8i)
 
 pci:v00009005d0000028Fsv00009005sd00000903*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-4i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-4i)
 
 pci:v00009005d0000028Fsv00009005sd00000904*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-8e)
 
 pci:v00009005d0000028Fsv00009005sd00000905*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-8e)
 
 pci:v00009005d0000028Fsv00009005sd00000906*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-4i4e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-4i4e)
 
 pci:v00009005d0000028Fsv00009005sd00000907*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100)
 
 pci:v00009005d0000028Fsv00009005sd00000908*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100)
 
 pci:v00009005d0000028Fsv00009005sd0000090A*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100A-8i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100A-8i)
 
 pci:v00009005d0000028Fsv00009005sd00001200*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-24i)
 
 pci:v00009005d0000028Fsv00009005sd00001201*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-8i16e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-8i16e)
 
 pci:v00009005d0000028Fsv00009005sd00001202*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-8i8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-8i8e)
 
 pci:v00009005d0000028Fsv00009005sd00001280*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-16i)
 
 pci:v00009005d0000028Fsv00009005sd00001281*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-16e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-16e)
 
 pci:v00009005d0000028Fsv00009005sd00001300*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-8i8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-8i8e)
 
 pci:v00009005d0000028Fsv00009005sd00001301*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 1100-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (HBA 1100-24i)
 
 pci:v00009005d0000028Fsv00009005sd00001302*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-8i8e)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-8i8e)
 
 pci:v00009005d0000028Fsv00009005sd00001303*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartHBA 2100-24i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartHBA 2100-24i)
 
 pci:v00009005d0000028Fsv00009005sd00001380*
- ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3154-16i)
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI SAS (SmartRAID 3154-16i)
 
 pci:v00009005d00000410*
  ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor HBA RAID)
index b459dc380ce088bea417928e83a71411dea0346d..4d3fcb63e1e1b44ccc56291ed2867662e8715d02 100644 (file)
@@ -1349,6 +1349,9 @@ usb:v03F0p3117*
 usb:v03F0p311D*
  ID_MODEL_FROM_DATABASE=Atheros AR9285 Malbec Bluetooth Adapter
 
+usb:v03F0p312A*
+ ID_MODEL_FROM_DATABASE=LaserJet Pro M701n
+
 usb:v03F0p3202*
  ID_MODEL_FROM_DATABASE=PhotoSmart 1215
 
@@ -4061,6 +4064,9 @@ usb:v041Ep3232*
 usb:v041Ep3237*
  ID_MODEL_FROM_DATABASE=SB X-Fi Surround 5.1 Pro
 
+usb:v041Ep3263*
+ ID_MODEL_FROM_DATABASE=SB X-Fi Surround 5.1 Pro
+
 usb:v041Ep3F00*
  ID_MODEL_FROM_DATABASE=E-Mu Xboard 25 MIDI Controller
 
@@ -8693,6 +8699,9 @@ usb:v046DpC22E*
 usb:v046DpC231*
  ID_MODEL_FROM_DATABASE=G13 Virtual Mouse
 
+usb:v046DpC232*
+ ID_MODEL_FROM_DATABASE=Gaming Virtual Keyboard
+
 usb:v046DpC245*
  ID_MODEL_FROM_DATABASE=G400 Optical Mouse
 
@@ -9884,6 +9893,9 @@ usb:v047FpC00E*
 usb:v047FpC03B*
  ID_MODEL_FROM_DATABASE=HD1
 
+usb:v047FpDA60*
+ ID_MODEL_FROM_DATABASE=DA60
+
 usb:v0480*
  ID_VENDOR_FROM_DATABASE=Toshiba America Inc
 
@@ -10212,7 +10224,7 @@ usb:v048Dp1172*
  ID_MODEL_FROM_DATABASE=Flash Drive
 
 usb:v048Dp1234*
- ID_MODEL_FROM_DATABASE=Mass storage
+ ID_MODEL_FROM_DATABASE=Chipsbank CBM2199 Flash Drive
 
 usb:v048Dp1336*
  ID_MODEL_FROM_DATABASE=SD/MMC Cardreader
@@ -15185,6 +15197,9 @@ usb:v04D9pA052*
 usb:v04D9pA055*
  ID_MODEL_FROM_DATABASE=Keyboard
 
+usb:v04D9pA075*
+ ID_MODEL_FROM_DATABASE=Optical Gaming Mouse
+
 usb:v04D9pA096*
  ID_MODEL_FROM_DATABASE=Keyboard
 
@@ -16359,7 +16374,7 @@ usb:v04E8p685E*
  ID_MODEL_FROM_DATABASE=GT-I9100 / GT-C3350 Phones (USB Debugging mode)
 
 usb:v04E8p6860*
- ID_MODEL_FROM_DATABASE=Galaxy series, misc. (MTP mode)
+ ID_MODEL_FROM_DATABASE=Galaxy A5 (MTP)
 
 usb:v04E8p6863*
  ID_MODEL_FROM_DATABASE=Galaxy series, misc. (tethering mode)
@@ -19197,7 +19212,7 @@ usb:v0525p1265*
  ID_MODEL_FROM_DATABASE=File-backed Storage Gadget
 
 usb:v0525p3424*
- ID_MODEL_FROM_DATABASE=Lumidigm Venus fingerprint sensor
+ ID_MODEL_FROM_DATABASE=V30x/V4xx fingerprint sensor [Lumidigm]
 
 usb:v0525pA0F0*
  ID_MODEL_FROM_DATABASE=Cambridge Electronic Devices Power1401 mk 2
@@ -19227,7 +19242,7 @@ usb:v0525pA4A4*
  ID_MODEL_FROM_DATABASE=Linux-USB user-mode bulk source/sink
 
 usb:v0525pA4A5*
- ID_MODEL_FROM_DATABASE=Pocketbook Pro 903 / Mobius 2 Action Cam / xDuoo X3
+ ID_MODEL_FROM_DATABASE=Pocketbook Pro 903 / Mobius 2 Action Cam / xDuoo X3 / PocketBook Pro 602
 
 usb:v0525pA4A6*
  ID_MODEL_FROM_DATABASE=Linux-USB Serial Gadget
@@ -20162,6 +20177,9 @@ usb:v054Cp035C*
 usb:v054Cp035F*
  ID_MODEL_FROM_DATABASE=UP-DR200 Photo Printer
 
+usb:v054Cp0360*
+ ID_MODEL_FROM_DATABASE=M2 Card Reader
+
 usb:v054Cp0382*
  ID_MODEL_FROM_DATABASE=Memory Stick PRO-HG Duo Adaptor (MSAC-UAH1)
 
@@ -23669,6 +23687,9 @@ usb:v059Fp106E*
 usb:v059Fp1094*
  ID_MODEL_FROM_DATABASE=Rugged THB
 
+usb:v059Fp1095*
+ ID_MODEL_FROM_DATABASE=Rugged
+
 usb:v059FpA601*
  ID_MODEL_FROM_DATABASE=HardDrive
 
@@ -23783,6 +23804,12 @@ usb:v05A7p4002*
 usb:v05A7p4003*
  ID_MODEL_FROM_DATABASE=Bluetooth Headset Series 2 in DFU mode
 
+usb:v05A7p400D*
+ ID_MODEL_FROM_DATABASE=SoundLink Color II speaker in DFU mode
+
+usb:v05A7p40FE*
+ ID_MODEL_FROM_DATABASE=SoundLink Color II speaker
+
 usb:v05A7pBC50*
  ID_MODEL_FROM_DATABASE=SoundLink Wireless Mobile speaker
 
@@ -24797,6 +24824,9 @@ usb:v05C8p036E*
 usb:v05C8p0374*
  ID_MODEL_FROM_DATABASE=HP EliteBook integrated HD Webcam
 
+usb:v05C8p038E*
+ ID_MODEL_FROM_DATABASE=HP Wide Vision HD integrated webcam
+
 usb:v05C8p03A1*
  ID_MODEL_FROM_DATABASE=XiaoMi Webcam
 
@@ -27480,7 +27510,7 @@ usb:v067Bp1231*
  ID_MODEL_FROM_DATABASE=Orico SATA External Hard Disk Drive Lay-Flat Docking Station with USB 3.0 & eSATA interfaces.
 
 usb:v067Bp2303*
- ID_MODEL_FROM_DATABASE=PL2303 Serial Port
+ ID_MODEL_FROM_DATABASE=PL2303 Serial Port / Mobile Action MA-8910P
 
 usb:v067Bp2305*
  ID_MODEL_FROM_DATABASE=PL2305 Parallel Port
@@ -28376,6 +28406,9 @@ usb:v06BCp020B*
 usb:v06BCp02BB*
  ID_MODEL_FROM_DATABASE=OKI PT390 POS Printer
 
+usb:v06BCp0383*
+ ID_MODEL_FROM_DATABASE=MC563 Multifunction Printer
+
 usb:v06BCp0A91*
  ID_MODEL_FROM_DATABASE=B2500MFP (printer+scanner)
 
@@ -30902,6 +30935,9 @@ usb:v0781pB6B7*
 usb:v0781pB6BA*
  ID_MODEL_FROM_DATABASE=CF SDDR-289
 
+usb:v0781pCFC9*
+ ID_MODEL_FROM_DATABASE=SDDR-489 ImageMate Pro Reader
+
 usb:v0782*
  ID_VENDOR_FROM_DATABASE=Trackerball
 
@@ -35930,6 +35966,9 @@ usb:v096E*
 usb:v096Ep0005*
  ID_MODEL_FROM_DATABASE=ePass2000
 
+usb:v096Ep0006*
+ ID_MODEL_FROM_DATABASE=HID Dongle (for OEMs - manufacturer string is "OEM")
+
 usb:v096Ep0120*
  ID_MODEL_FROM_DATABASE=Microcosm Ltd Dinkey
 
@@ -37316,6 +37355,9 @@ usb:v0A5Fp0009*
 usb:v0A5Fp0050*
  ID_MODEL_FROM_DATABASE=P120i / WM120i
 
+usb:v0A5Fp0080*
+ ID_MODEL_FROM_DATABASE=GK420d Label Printer
+
 usb:v0A5Fp0081*
  ID_MODEL_FROM_DATABASE=GK420t Label Printer
 
@@ -37433,6 +37475,9 @@ usb:v0A82*
 usb:v0A82p4600*
  ID_MODEL_FROM_DATABASE=TravelScan 460/464
 
+usb:v0A82p6605*
+ ID_MODEL_FROM_DATABASE=ScanShell 800N
+
 usb:v0A83*
  ID_VENDOR_FROM_DATABASE=NextComm, Inc.
 
@@ -40406,6 +40451,9 @@ usb:v0BDApB72A*
 usb:v0BDApB812*
  ID_MODEL_FROM_DATABASE=RTL88x2bu [AC1200 Techkey]
 
+usb:v0BDApF179*
+ ID_MODEL_FROM_DATABASE=RTL8188FTV 802.11b/g/n 1T1R 2.4G WLAN Adapter
+
 usb:v0BDB*
  ID_VENDOR_FROM_DATABASE=Ericsson Business Mobile Networks BV
 
@@ -40868,6 +40916,12 @@ usb:v0C3D*
 usb:v0C3E*
  ID_VENDOR_FROM_DATABASE=Nextcell, Inc.
 
+usb:v0C40*
+ ID_VENDOR_FROM_DATABASE=ELMCU
+
+usb:v0C40p8000*
+ ID_MODEL_FROM_DATABASE=2.4GHz receiver
+
 usb:v0C44*
  ID_VENDOR_FROM_DATABASE=Motorola iDEN
 
@@ -40964,6 +41018,9 @@ usb:v0C45p184C*
 usb:v0C45p1A90*
  ID_MODEL_FROM_DATABASE=2M pixel Microscope Camera (with capture button) [Andonstar V160]
 
+usb:v0C45p5004*
+ ID_MODEL_FROM_DATABASE=Redragon Mitra RGB Keyboard
+
 usb:v0C45p5101*
  ID_MODEL_FROM_DATABASE=2.4G Wireless Device [Rii MX3]
 
@@ -45360,31 +45417,37 @@ usb:v0F6E*
  ID_VENDOR_FROM_DATABASE=INTELLIGENT SYSTEMS
 
 usb:v0F6Ep0100*
- ID_MODEL_FROM_DATABASE=GameBoy Color Emulator
+ ID_MODEL_FROM_DATABASE=IS-CGB-EMULATOR
 
 usb:v0F6Ep0201*
  ID_MODEL_FROM_DATABASE=GameBoy Advance Flash Gang Writer
 
 usb:v0F6Ep0202*
- ID_MODEL_FROM_DATABASE=GameBoy Advance Capture
+ ID_MODEL_FROM_DATABASE=IS-AGB-CAPTURE
 
 usb:v0F6Ep0300*
- ID_MODEL_FROM_DATABASE=Gamecube DOL Viewer
+ ID_MODEL_FROM_DATABASE=IS-DOL-VIEWER
 
 usb:v0F6Ep0400*
- ID_MODEL_FROM_DATABASE=NDS Emulator
+ ID_MODEL_FROM_DATABASE=IS-NITRO-EMULATOR
 
 usb:v0F6Ep0401*
- ID_MODEL_FROM_DATABASE=NDS UIC
+ ID_MODEL_FROM_DATABASE=IS-NITRO-UIC
 
 usb:v0F6Ep0402*
- ID_MODEL_FROM_DATABASE=NDS Writer
+ ID_MODEL_FROM_DATABASE=IS-NITRO-WRITER
 
 usb:v0F6Ep0403*
- ID_MODEL_FROM_DATABASE=NDS Capture
+ ID_MODEL_FROM_DATABASE=IS-NITRO-CAPTURE
 
 usb:v0F6Ep0404*
- ID_MODEL_FROM_DATABASE=NDS Emulator (Lite)
+ ID_MODEL_FROM_DATABASE=IS-NITRO-EMULATOR (DS Lite)
+
+usb:v0F6Ep0500*
+ ID_MODEL_FROM_DATABASE=IS-TWL-DEBUGGER
+
+usb:v0F6Ep0501*
+ ID_MODEL_FROM_DATABASE=IS-TWL-CAPTURE
 
 usb:v0F73*
  ID_VENDOR_FROM_DATABASE=DFI
@@ -52736,6 +52799,9 @@ usb:v1504*
 usb:v1504p001F*
  ID_MODEL_FROM_DATABASE=SRP-350II Thermal Receipt Printer
 
+usb:v1508*
+ ID_VENDOR_FROM_DATABASE=Fibocom
+
 usb:v1509*
  ID_VENDOR_FROM_DATABASE=First International Computer, Inc.
 
@@ -53255,6 +53321,9 @@ usb:v1532p004C*
 usb:v1532p004D*
  ID_MODEL_FROM_DATABASE=DeathAdder 2000 (Cynosa Pro Bundle)
 
+usb:v1532p004F*
+ ID_MODEL_FROM_DATABASE=RZ01-0145, Gaming Mouse [DeathAdder 2000 (Alternate)]
+
 usb:v1532p0050*
  ID_MODEL_FROM_DATABASE=Naga Hex V2
 
@@ -53345,14 +53414,23 @@ usb:v1532p007B*
 usb:v1532p007E*
  ID_MODEL_FROM_DATABASE=RC30-030502 Mouse Dock
 
+usb:v1532p0083*
+ ID_MODEL_FROM_DATABASE=RC30-0315, Gaming Mouse [Basilisk X HyperSpeed]
+
 usb:v1532p0084*
  ID_MODEL_FROM_DATABASE=RZ01-0321 Gaming Mouse [DeathAdder V2]
 
 usb:v1532p0085*
  ID_MODEL_FROM_DATABASE=RZ01-0316 Gaming Mouse [Basilisk V2]
 
+usb:v1532p0086*
+ ID_MODEL_FROM_DATABASE=Gaming Mouse [Basilisk Ultimate, Wired]
+
 usb:v1532p0088*
- ID_MODEL_FROM_DATABASE=Razer Basilisk Ultimate Dongle
+ ID_MODEL_FROM_DATABASE=Gaming Mouse [Basilisk Ultimate, Wireless, Receiver]
+
+usb:v1532p008A*
+ ID_MODEL_FROM_DATABASE=RZ01-0325, Gaming Mouse [Viper Mini]
 
 usb:v1532p0101*
  ID_MODEL_FROM_DATABASE=Copperhead Mouse
@@ -53585,6 +53663,12 @@ usb:v1532p0253*
 usb:v1532p0255*
  ID_MODEL_FROM_DATABASE=RZ09-0328, Gaming Laptop [Blade 15 Base Model (2020)]
 
+usb:v1532p0256*
+ ID_MODEL_FROM_DATABASE=RZ09--0329, Gaming Laptop [Blade Pro 17 Full HD (2020)]
+
+usb:v1532p025D*
+ ID_MODEL_FROM_DATABASE=RZ03-0338, Gaming Keyboard [Ornata V2]
+
 usb:v1532p0300*
  ID_MODEL_FROM_DATABASE=RZ06-0063 Motion Sensing Controllers [Hydra]
 
@@ -53627,6 +53711,12 @@ usb:v1532p051C*
 usb:v1532p051D*
  ID_MODEL_FROM_DATABASE=Nari (Wired)
 
+usb:v1532p051E*
+ ID_MODEL_FROM_DATABASE=RC30-026902, Gaming Headset [Nari Essential, Wireless, Receiver]
+
+usb:v1532p051F*
+ ID_MODEL_FROM_DATABASE=RC30-026901, Gaming Headset [Nari Essential, Wired]
+
 usb:v1532p0520*
  ID_MODEL_FROM_DATABASE=Kraken Tournament Edition
 
@@ -53648,6 +53738,9 @@ usb:v1532p0A02*
 usb:v1532p0A03*
  ID_MODEL_FROM_DATABASE=Wildcat
 
+usb:v1532p0A15*
+ ID_MODEL_FROM_DATABASE=RZ06-0199, Gaming Controller [Wolverine Tournament Edition]
+
 usb:v1532p0C00*
  ID_MODEL_FROM_DATABASE=RZ02-0135 Hard Gaming Mouse Mat [Firefly]
 
@@ -54254,6 +54347,21 @@ usb:v1605*
 usb:v1605p0001*
  ID_MODEL_FROM_DATABASE=DIO-32 (No Firmware Yet)
 
+usb:v1605p0002*
+ ID_MODEL_FROM_DATABASE=USB-DIO-48 (No Firmware Yet)
+
+usb:v1605p0003*
+ ID_MODEL_FROM_DATABASE=USB-DIO-96 (No Firmware Yet)
+
+usb:v1605p0004*
+ ID_MODEL_FROM_DATABASE=USB-DIO-32I (No Firmware Yet)
+
+usb:v1605p0005*
+ ID_MODEL_FROM_DATABASE=USB-DIO24 (based on -CTR6) (No Firmware Yet)
+
+usb:v1605p0006*
+ ID_MODEL_FROM_DATABASE=USB-DIO24-CTR6 (No Firmware Yet)
+
 usb:v1606*
  ID_VENDOR_FROM_DATABASE=Umax
 
index e742a33ea69e8eb4176994dd6c61b074ef1d4c8a..3b42f5a2e702b294b4f535459347586d64bd3725 100644 (file)
@@ -5,8 +5,8 @@
 # Match string formats:
 # <subsystem>:<modalias>
 #
-# pci:v<vendor>d<device>
-# usb:v<vendor>p<product>
+# pci:v<vendor>d<device>:
+# usb:v<vendor>p<product>:
 #
 # To add local entries, create a new file
 #   /etc/udev/hwdb.d/61-autosuspend-local.hwdb
@@ -24,8 +24,9 @@
 #
 # Allowed properties are:
 #    ID_AUTOSUSPEND=1
-
 #
+# All matches should end in ':*' to allow future expansions of the match key.
+
 # Sort by brand, model
 
 #########################################
 #########################################
 
 # AU9540 Smartcard Reader
-usb:v058Fp9540*
+usb:v058Fp9540:*
+ ID_AUTOSUSPEND=1
+
+#########################################
+# Lenovo
+#########################################
+
+# X1C8 Touchscreen
+usb:v04F3p2B7C:*
+# T14 Gen 1 Touchscreen
+usb:v04F3p2ACC:*
  ID_AUTOSUSPEND=1
 
 #########################################
@@ -41,14 +52,14 @@ usb:v058Fp9540*
 #########################################
 
 # Emulated USB HID devices
-usb:v0627p0001:*QEMU USB Keyboard*
-usb:v0627p0001:*QEMU USB Mouse*
-usb:v0627p0001:*QEMU USB Tablet*
+usb:v0627p0001:*QEMU USB Keyboard*:*
+usb:v0627p0001:*QEMU USB Mouse*:*
+usb:v0627p0001:*QEMU USB Tablet*:*
  ID_AUTOSUSPEND=1
 
 #########################################
 # Wacom
 #########################################
 
-usb:v056Ap51A0*
+usb:v056Ap51A0:*
  ID_AUTOSUSPEND=1
index bf9f68a858f80c94342820d8b79e9dd180a93414..31475ed71ce43e3fac7a53888927334588b14dc9 100644 (file)
@@ -3,10 +3,10 @@
 # The lookup keys are composed in:
 #   60-evdev.rules
 #
-# Note: The format of the "evdev:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
+# Note: The format of the "evdev:" prefix match key is a contract between the
+# rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily expected to be a stable
+# ABI.
 #
 # Match string formats:
 # evdev:<modalias>
@@ -17,8 +17,8 @@
 # and add your rules there. To load the new rules execute (as root):
 #   systemd-hwdb update
 #   udevadm trigger /dev/input/eventXX
-# where /dev/input/eventXX is the device in question. If in
-# doubt, simply use /dev/input/event* to reload all input rules.
+# where /dev/input/eventXX is the device in question. If in doubt, simply use
+# /dev/input/event* to reload all input rules.
 #
 # If your changes are generally applicable, preferably send them as a pull
 # request to
 # Allowed properties are:
 #    EVDEV_ABS_<axis>=<min>:<max>:<res>:<fuzz>:<flat>
 #
-# where <axis> is the hexadecimal EV_ABS code as listed in linux/input.h
-# and min, max, res, fuzz, flat are the decimal values to the respective
-# fields of the struct input_absinfo as listed in linux/input.h.
-# If a field is missing the field will be left as-is. Not all fields need to
-# be present. e.g. ::45 sets the resolution to 45 units/mm.
-
+# where <axis> is the hexadecimal EV_ABS code as listed in linux/input.h and
+# min, max, res, fuzz, flat are the decimal values to the respective fields of
+# the struct input_absinfo as listed in linux/input.h. If a field is missing
+# the field will be left as-is. Not all fields need to be present. e.g. ::45
+# sets the resolution to 45 units/mm.
 #
+# All matches should end in ':*' to allow future expansions of the match key.
+
 # Sort by brand, model
 
 #########################################
@@ -44,7 +45,9 @@
 #########################################
 
 # Hyperpen 12000U
-evdev:input:b0003v08CAp0010*
+evdev:input:b0003v08CAp0010:*
+# Hyperpen 6000U
+evdev:input:b0003v08CAp0020:*
  EVDEV_ABS_00=::20
  EVDEV_ABS_01=::20
 
@@ -53,48 +56,48 @@ evdev:input:b0003v08CAp0010*
 #########################################
 
 # Macbook2,1 (late 2006), single-button touchpad
-evdev:input:b0003v05ACp021B*
+evdev:input:b0003v05ACp021B:*
 # Macbook4,1
-evdev:input:b0003v05ACp0229*
-evdev:input:b0003v05ACp022A*
+evdev:input:b0003v05ACp0229:*
+evdev:input:b0003v05ACp022A:*
  EVDEV_ABS_00=256:1471:12
  EVDEV_ABS_01=256:831:12
 
 # Macbook5,1 (unibody), aka wellspring3
-evdev:input:b0003v05ACp0236*
-evdev:input:b0003v05ACp0237*
-evdev:input:b0003v05ACp0238*
+evdev:input:b0003v05ACp0236:*
+evdev:input:b0003v05ACp0237:*
+evdev:input:b0003v05ACp0238:*
  EVDEV_ABS_00=::92
  EVDEV_ABS_01=::90
  EVDEV_ABS_35=::92
  EVDEV_ABS_36=::90
 
 # Macbook8 (unibody, March 2011)
-evdev:input:b0003v05ACp0245*
-evdev:input:b0003v05ACp0246*
-evdev:input:b0003v05ACp0247*
+evdev:input:b0003v05ACp0245:*
+evdev:input:b0003v05ACp0246:*
+evdev:input:b0003v05ACp0247:*
  EVDEV_ABS_00=::92
  EVDEV_ABS_01=::91
  EVDEV_ABS_35=::92
  EVDEV_ABS_36=::91
 
 # Macbook8,2 (unibody)
-evdev:input:b0003v05ACp0252*
-evdev:input:b0003v05ACp0253*
-evdev:input:b0003v05ACp0254*
+evdev:input:b0003v05ACp0252:*
+evdev:input:b0003v05ACp0253:*
+evdev:input:b0003v05ACp0254:*
  EVDEV_ABS_00=::94
  EVDEV_ABS_01=::92
  EVDEV_ABS_35=::94
  EVDEV_ABS_36=::92
 
 # MacbookPro10,1 (unibody, June 2012)
-evdev:input:b0003v05ACp0262*
-evdev:input:b0003v05ACp0263*
-evdev:input:b0003v05ACp0264*
+evdev:input:b0003v05ACp0262:*
+evdev:input:b0003v05ACp0263:*
+evdev:input:b0003v05ACp0264:*
 # MacbookPro10,2 (unibody, October 2012)
-evdev:input:b0003v05ACp0259*
-evdev:input:b0003v05ACp025A*
-evdev:input:b0003v05ACp025B*
+evdev:input:b0003v05ACp0259:*
+evdev:input:b0003v05ACp025A:*
+evdev:input:b0003v05ACp025B:*
  EVDEV_ABS_00=::94
  EVDEV_ABS_01=::92
  EVDEV_ABS_35=::94
@@ -131,7 +134,7 @@ evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro14,3:*
 #########################################
 
 # Asus N53SV
-evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnASUSTeKComputerInc.:pnN53SV*
+evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnASUSTeKComputerInc.:pnN53SV:*
  EVDEV_ABS_00=0:1152:14
  EVDEV_ABS_01=0:576:10
  EVDEV_ABS_35=0:1152:14
@@ -143,7 +146,7 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnASUSTeKComputerInc.:pnF3Sg:*
  EVDEV_ABS_01=1103:5856:61
 
 # Asus VivoBook E402SA
-evdev:name:Elan Touchpad:dmi:*svnASUSTeKCOMPUTERINC.:pnE402SA*
+evdev:name:Elan Touchpad:dmi:*svnASUSTeKCOMPUTERINC.:pnE402SA:*
  EVDEV_ABS_00=::29
  EVDEV_ABS_01=::29
  EVDEV_ABS_35=::29
@@ -195,26 +198,26 @@ evdev:name:SYNA3602:00 0911:5288 Touchpad:dmi:*svnBANGHO:pnCLOUDPRO:*
 #########################################
 
 # Dell Vostro 1510
-evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510*
+evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510:*
  EVDEV_ABS_00=::14
  EVDEV_ABS_01=::18
 
 # Dell Inspiron 3537 - PS/2
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnDellInc.:pnInspiron3537*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnDellInc.:pnInspiron3537:*
  EVDEV_ABS_00=1268:5675:41
  EVDEV_ABS_01=1101:4792:61
  EVDEV_ABS_35=1268:5675:41
  EVDEV_ABS_36=1101:4792:61
 
 # Dell Inspiron 3537 - RMI4
-evdev:name:Synaptics TM2382-001:dmi:*svnDellInc.:pnInspiron3537*
+evdev:name:Synaptics TM2382-001:dmi:*svnDellInc.:pnInspiron3537:*
  EVDEV_ABS_00=::24
  EVDEV_ABS_01=::34
  EVDEV_ABS_35=::24
  EVDEV_ABS_36=::34
 
 # Dell Inspiron N5040
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040:*
  EVDEV_ABS_00=25:2000:22
  EVDEV_ABS_01=0:1351:28
  EVDEV_ABS_35=25:2000:22
@@ -226,42 +229,42 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*bvn*:bvr*:bd*:svnDellInc.:pnMM061:*
  EVDEV_ABS_01=687:5176:107
 
 # Dell Latitude E6220
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6220*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6220:*
  EVDEV_ABS_00=76:1815:22
  EVDEV_ABS_01=131:1330:30
  EVDEV_ABS_35=76:1815:22
  EVDEV_ABS_36=131:1330:30
 
 # Dell Latitude E6320
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320:*
  EVDEV_ABS_00=79:1841:22
  EVDEV_ABS_01=140:1325:29
  EVDEV_ABS_35=79:1841:22
  EVDEV_ABS_36=140:1325:29
 
 # Dell Latitude E7250
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7250*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7250:*
  EVDEV_ABS_00=179:3903:38
  EVDEV_ABS_01=277:1916:32
  EVDEV_ABS_35=179:3903:38
  EVDEV_ABS_36=277:1916:32
 
 # Dell Latitude E7470
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470:*
  EVDEV_ABS_00=29:2930:30
  EVDEV_ABS_01=26:1533:29
  EVDEV_ABS_35=29:2930:30
  EVDEV_ABS_36=26:1533:29
 
 # Dell Precision 5510
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnPrecision5510*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnPrecision5510:*
  EVDEV_ABS_00=::42
  EVDEV_ABS_01=::43
  EVDEV_ABS_35=::42
  EVDEV_ABS_36=::43
 
 # Dell Precision M4700
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnDellInc.:pnPrecisionM4700*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnDellInc.:pnPrecisionM4700:*
  EVDEV_ABS_00=0:1960:24
  EVDEV_ABS_01=113:1436:30
  EVDEV_ABS_35=0:1960:24
@@ -275,14 +278,14 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnDellInc.:pnXPS139360:cvr:*
  EVDEV_ABS_36=::60
 
 # Dell XPS15 9550
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPS159550*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPS159550:*
  EVDEV_ABS_00=::41
  EVDEV_ABS_01=::43
  EVDEV_ABS_35=::41
  EVDEV_ABS_36=::43
 
 # Dell XPS M1530
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPSM1530*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPSM1530:*
  EVDEV_ABS_00=85:947:15
  EVDEV_ABS_01=154:726:18
 
@@ -291,7 +294,7 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPSM1530*
 #####
 
 # Fujitsu Component - USB Touch Panel
-evdev:input:b0003v0430p0530*
+evdev:input:b0003v0430p0530:*
  EVDEV_ABS_00=0:4096:16
  EVDEV_ABS_01=0:4096:16
 
@@ -300,7 +303,7 @@ evdev:input:b0003v0430p0530*
 #########################################
 
 # Chromebook Pixel (2015) - Samus
-evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus*
+evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus:*
  EVDEV_ABS_00=::10
  EVDEV_ABS_01=::10
  EVDEV_ABS_35=::10
@@ -311,28 +314,28 @@ evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus*
 #########################################
 
 # HP Chromebook 14 (Falco)
-evdev:name:Cypress APA Trackpad ?cyapa?:dmi:*:svnHewlett-Packard*:pnFalco*:
+evdev:name:Cypress APA Trackpad ?cyapa?:dmi:*:svnHewlett-Packard*:pnFalco*:*
  EVDEV_ABS_00=:::8
  EVDEV_ABS_01=:::8
  EVDEV_ABS_35=:::8
  EVDEV_ABS_36=:::8
 
 # HP Pavilion dm4
-evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondm4*
+evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondm4:*
  EVDEV_ABS_00=1360:5563:47
  EVDEV_ABS_01=1269:4618:61
  EVDEV_ABS_35=1360:5563:47
  EVDEV_ABS_36=1269:4618:61
 
 # HP Pavilion g6
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvnHewlett-Packard:*svnHewlett-Packard:pnHPPaviliong6*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvnHewlett-Packard:*svnHewlett-Packard:pnHPPaviliong6:*
  EVDEV_ABS_00=1255:5728:50
  EVDEV_ABS_01=1215:4761:71
  EVDEV_ABS_35=1255:5728:50
  EVDEV_ABS_36=1215:4761:71
 
 # HP Pavilion dv7
-evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondv7*
+evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondv7:*
  EVDEV_ABS_00=1068:5805:44
  EVDEV_ABS_01=1197:4890:57
  EVDEV_ABS_35=1068:5805:44
@@ -346,14 +349,14 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnHP:pnHPLaptop15-bs0xx:*
  EVDEV_ABS_36=1029:4916:78
 
 # HP Spectre
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnHP:pnHPSpectreNotebook*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnHP:pnHPSpectreNotebook:*
  EVDEV_ABS_00=1205:5691:47
  EVDEV_ABS_01=1083:4808:65
  EVDEV_ABS_35=1205:5691:47
  EVDEV_ABS_36=1083:4808:65
 
 # HP Envy x360
-evdev:name:SynPS/2 Synaptics TouchPad:*svnHP:pnHPENVYx360Convertible15m-cn0xxx*
+evdev:name:SynPS/2 Synaptics TouchPad:*svnHP:pnHPENVYx360Convertible15m-cn0xxx:*
  EVDEV_ABS_00=1302:5640:36
  EVDEV_ABS_01=1119:4741:61
  EVDEV_ABS_35=1302:5640:36
@@ -364,28 +367,28 @@ evdev:name:SynPS/2 Synaptics TouchPad:*svnHP:pnHPENVYx360Convertible15m-cn0xxx*
 #########################################
 
 # Lenovo B590
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrLenovoB590*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrLenovoB590:*
  EVDEV_ABS_00=1243:5759:48
  EVDEV_ABS_01=1130:4832:65
  EVDEV_ABS_35=1243:5759:48
  EVDEV_ABS_36=1130:4832:65
 
 # Lenovo E530
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:pn*ThinkPadEdgeE530*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:pn*ThinkPadEdgeE530:*
  EVDEV_ABS_00=1241:5703:49
  EVDEV_ABS_01=1105:4820:68
  EVDEV_ABS_35=1241:5703:49
  EVDEV_ABS_36=1105:4820:68
 
 # Lenovo L430
-evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnLENOVO*:pvrThinkPadL430*
+evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnLENOVO*:pvrThinkPadL430:*
  EVDEV_ABS_00=19:2197:29
  EVDEV_ABS_01=12:1151:25
  EVDEV_ABS_35=19:2197:29
  EVDEV_ABS_36=12:1151:25
 
 # Lenovo P50
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*P50*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*P50:*
  EVDEV_ABS_00=::44
  EVDEV_ABS_01=::67
  EVDEV_ABS_35=::44
@@ -408,129 +411,129 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX240?:*
  EVDEV_ABS_36=1159:4700:53
 
 # Lenovo ThinkPad X140e
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX140e*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX140e:*
  EVDEV_ABS_00=1176:5767:62
  EVDEV_ABS_01=416:5534:160
  EVDEV_ABS_35=1176:5767:62
  EVDEV_ABS_36=416:5534:160
 
 # Lenovo ThinkPad T430
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadT430*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadT430:*
  EVDEV_ABS_00=1250:5631:58
  EVDEV_ABS_01=1309:4826:78
  EVDEV_ABS_35=1250:5631:58
  EVDEV_ABS_36=1309:4826:78
 
 # Lenovo Thinkpad Carbon X1 4th gen. and X1 Yoga 1st gen.
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon4th*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon4th:*
  EVDEV_ABS_00=1262:5679:44
  EVDEV_ABS_01=1101:4824:65
  EVDEV_ABS_35=1262:5679:44
  EVDEV_ABS_36=1101:4824:65
 
 # Lenovo Thinkpad Carbon X1 5th gen.
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th:*
  EVDEV_ABS_00=::44
  EVDEV_ABS_01=::65
  EVDEV_ABS_35=::44
  EVDEV_ABS_36=::65
 
 # Lenovo Thinkpad Carbon X1 5th gen. (rmi4)
-evdev:name:Synaptics TM3289-002:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th*
+evdev:name:Synaptics TM3289-002:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th:*
  EVDEV_ABS_00=::19
  EVDEV_ABS_01=::19
  EVDEV_ABS_35=::19
  EVDEV_ABS_36=::19
 
 # Lenovo Thinkpad X1 Tablet Gen3
-evdev:input:b0003v17EFp60B5*
+evdev:input:b0003v17EFp60B5:*
  EVDEV_ABS_00=::12
  EVDEV_ABS_01=::11
  EVDEV_ABS_35=::12
  EVDEV_ABS_36=::11
 
 # Lenovo T460
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T460*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T460:*
  EVDEV_ABS_00=1266:5677:44
  EVDEV_ABS_01=1093:4832:65
  EVDEV_ABS_35=1266:5677:44
  EVDEV_ABS_36=1093:4832:65
 
 # Lenovo T510
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510:*
  EVDEV_ABS_00=778:6239:72
  EVDEV_ABS_01=841:5330:100
  EVDEV_ABS_35=778:6239:72
  EVDEV_ABS_36=841:5330:100
 
 # Lenovo V360
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrLenovoV360*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrLenovoV360:*
  EVDEV_ABS_00=1243:5927:60
  EVDEV_ABS_01=902:5330:108
 
 # Lenovo W530
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadW530*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadW530:*
  EVDEV_ABS_00=1250:5631:59
  EVDEV_ABS_01=1205:4834:81
  EVDEV_ABS_35=1250:5631:59
  EVDEV_ABS_36=1205:4834:81
 
 # Lenovo X220 series
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadX220*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadX220:*
  EVDEV_ABS_00=1316:5627:58
  EVDEV_ABS_01=1355:4826:81
  EVDEV_ABS_35=1316:5627:58
  EVDEV_ABS_36=1355:4826:81
 
 # Lenovo X230 series
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230:*
  EVDEV_ABS_01=::100
  EVDEV_ABS_36=::100
 
 # Lenovo Y700-14ISK
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapadY700-14ISK*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapadY700-14ISK:*
  EVDEV_ABS_00=::27
  EVDEV_ABS_01=::29
  EVDEV_ABS_35=::27
  EVDEV_ABS_36=::29
 
 # Lenovo Ideapad 310S-14ISK
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapad310S-14ISK*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapad310S-14ISK:*
  EVDEV_ABS_00=113:3960:37
  EVDEV_ABS_01=100:1959:27
  EVDEV_ABS_35=113:3960:37
  EVDEV_ABS_36=100:1959:27
 
 # Lenovo Ideapad 500S-13ISK
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapad500S-13ISK*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapad500S-13ISK:*
  EVDEV_ABS_00=125:3955:37
  EVDEV_ABS_01=104:1959:27
  EVDEV_ABS_35=125:3954:37
  EVDEV_ABS_36=104:1959:27
 
 # Lenovo Yoga 500-14ISK
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14ISK*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14ISK:*
  EVDEV_ABS_00=124:3955:36
  EVDEV_ABS_01=103:1959:26
  EVDEV_ABS_35=124:3955:36
  EVDEV_ABS_36=103:1959:26
 
 # Lenovo Flex 3 15-inch
-evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnLENOVO*:pvrFlex3-15*
+evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnLENOVO*:pvrFlex3-15:*
  EVDEV_ABS_00=::38
  EVDEV_ABS_01=::28
  EVDEV_ABS_35=::38
  EVDEV_ABS_36=::28
 
 # Lenovo ThinkPad Edge 13 (02173BG)
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*02173BG*:*pvrThinkPadEdge*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*02173BG*:*pvrThinkPadEdge:*
  EVDEV_ABS_00=916:6077:55
  EVDEV_ABS_01=653:5395:116
  EVDEV_ABS_35=916:6077:55
  EVDEV_ABS_36=653:5395:116
 
 # Lenovo Yoga 500-14IBD, 80N4
-evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14IBD*
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14IBD:*
  EVDEV_ABS_00=117:3952:36
  EVDEV_ABS_01=105:1960:26
  EVDEV_ABS_35=117:3952:36
@@ -544,7 +547,7 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:*
  EVDEV_ABS_36=::52
 
 # Lenovo Legion Y9000X2020
-evdev:name:MSFT0001:02 04F3:304B Touchpad:dmi:*svnLENOVO:*pvrLenovoLegionY9000X2020*
+evdev:name:MSFT0001:02 04F3:304B Touchpad:dmi:*svnLENOVO:*pvrLenovoLegionY9000X2020:*
  EVDEV_ABS_00=::31
  EVDEV_ABS_01=::30
  EVDEV_ABS_35=::31
@@ -562,7 +565,7 @@ evdev:name:1A58675*:00 06CB:8323 Touchpad:dmi:*svnRazer:pnBladeStealth:*
  EVDEV_ABS_36=::11:8
 
 # Razer Blade Stealth (2016)
-evdev:name:Synaptics TM2438-005:dmi:*svnRazer:pnBladeStealth*
+evdev:name:Synaptics TM2438-005:dmi:*svnRazer:pnBladeStealth:*
  EVDEV_ABS_00=0:4064:29
  EVDEV_ABS_01=0:2405:37
  EVDEV_ABS_35=0:4064:29
@@ -573,14 +576,14 @@ evdev:name:Synaptics TM2438-005:dmi:*svnRazer:pnBladeStealth*
 #########################################
 
 # Samsung 305V4
-evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn305V4A/305V5A*
+evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn305V4A/305V5A:*
  EVDEV_ABS_00=0:2480:28
  EVDEV_ABS_01=0:1116:24
  EVDEV_ABS_35=0:2480:28
  EVDEV_ABS_36=0:1116:24
 
 # Samsung 880Z5E
-evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn870Z5E/880Z5E/680Z5E*
+evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn870Z5E/880Z5E/680Z5E:*
  EVDEV_ABS_00=::30
  EVDEV_ABS_01=::29
  EVDEV_ABS_35=::30
@@ -591,7 +594,7 @@ evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn870Z5E/
 #########################################
 
 # Star LabTop Mk III
-evdev:name:ALPS0001:00 0911:5288 Touchpad:dmi:*svnStarLabs:pnLabTop*
+evdev:name:ALPS0001:00 0911:5288 Touchpad:dmi:*svnStarLabs:pnLabTop:*
  EVDEV_ABS_00=0:2627:25
  EVDEV_ABS_01=0:1331:20
  EVDEV_ABS_35=0:2627:25
@@ -620,12 +623,12 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnSystem76:pnGalagoPro:pvrgalp2:*
 #########################################
 
 # Toshiba Tecra M11
-evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnTOSHIBA:pnTECRAM11*
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnTOSHIBA:pnTECRAM11:*
  EVDEV_ABS_00=90:962:11
  EVDEV_ABS_01=51:681:14
 
 # Toshiba Satellite R830
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnTOSHIBA:pnSATELLITER830*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnTOSHIBA:pnSATELLITER830:*
  EVDEV_ABS_00=1238:5785:53
  EVDEV_ABS_01=1045:4826:76
  EVDEV_ABS_35=1238:5785:53
@@ -636,7 +639,7 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnTOSHIBA:pnSATELLITER830*
 #########################################
 
 # Trust Flex Graphics Tablet
-evdev:input:b0003v2179p0004*
+evdev:input:b0003v2179p0004:*
  EVDEV_ABS_00=::234
  EVDEV_ABS_01=::328
 
@@ -645,11 +648,11 @@ evdev:input:b0003v2179p0004*
 #########################################
 
 # WALTOP International Corp. Slim Tablet
-evdev:input:b0003v172Fp0031*
+evdev:input:b0003v172Fp0031:*
  EVDEV_ABS_00=0:10000:400
  EVDEV_ABS_01=0:6250:400
 
 #WALTOP International Corp. Graphics Tablet
-evdev:input:b0003v172Fp0047*
+evdev:input:b0003v172Fp0047:*
  EVDEV_ABS_00=0:20000:80
  EVDEV_ABS_01=0:12500:80
index 9e28db1e493d7576cfb4e505c7d805d7def24eda..3fe850847bcd6cd857fb914e34cc540bc883e1df 100644 (file)
@@ -3,13 +3,13 @@
 # The lookup keys are composed in:
 #   60-input-id.rules
 #
-# Note: The format of the "input-id:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
+# Note: The format of the "input-id:" prefix match key is a contract between
+# the rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily expected to be a stable
+# ABI.
 #
 # Match string formats:
-# id-input:modalias:<modalias>
+# id-input:modalias:<modalias pattern>
 #
 # To add local entries, create a new file
 #   /etc/udev/hwdb.d/61-input-id-local.hwdb
 #   udevadm info /dev/input/eventXX.
 #
 # This file must only be used where the input_id builtin assigns the wrong
-# properties or lacks the assignment of some properties. This is almost
-# always caused by a device not adhering to the standard of the device's
-# type.
+# properties or lacks the assignment of some properties. This is almost always
+# caused by a device not adhering to the standard of the device's type.
 #
 # Allowed properties are:
-#    ID_INPUT
-#    ID_INPUT_ACCELEROMETER, ID_INPUT_MOUSE,
-#    ID_INPUT_POINTINGSTICK, ID_INPUT_TOUCHSCREEN, ID_INPUT_TOUCHPAD,
-#    ID_INPUT_TABLET, ID_INPUT_TABLET_PAD, ID_INPUT_JOYSTICK, ID_INPUT_KEY,
-#    ID_INPUT_KEYBOARD, ID_INPUT_SWITCH, ID_INPUT_TRACKBALL
+#    ID_INPUT, ID_INPUT_ACCELEROMETER, ID_INPUT_MOUSE, ID_INPUT_POINTINGSTICK,
+#    ID_INPUT_TOUCHSCREEN, ID_INPUT_TOUCHPAD, ID_INPUT_TABLET,
+#    ID_INPUT_TABLET_PAD, ID_INPUT_JOYSTICK, ID_INPUT_KEY, ID_INPUT_KEYBOARD,
+#    ID_INPUT_SWITCH, ID_INPUT_TRACKBALL
 #
 #    ID_INPUT
 #       * MUST be set when ANY of ID_INPUT_* is set
 #    ID_INPUT_TABLET
 #       * MUST be set when setting ID_INPUT_TABLET_PAD
 #
-# Allowed values are 1 and 0 to set or unset, repsectively.
+# Allowed values are 1 and 0 to set or unset, respectively.
 #
 # NOT allowed in this file are:
 #    ID_INPUT_WIDTH_MM, ID_INPUT_HEIGHT_MM, ID_INPUT_TOUCHPAD_INTEGRATION
 #
+# All matches should end in ':*' to allow future expansions of the match key.
 
 # Example:
-# id-input:modalias:input:b0003v1234pABCD*
+# id-input:modalias:input:b0003v1234pABCD:*
 #  ID_INPUT_TOUCHPAD=1
 #  ID_INPUT=1
 
 # Sort by brand, model
 
 # UC-Logic TABLET 1060N Pad
-id-input:modalias:input:b0003v5543p0081*
+id-input:modalias:input:b0003v5543p0081:*
  ID_INPUT_TABLET=1
  ID_INPUT_TABLET_PAD=1
 
 # XP-PEN STAR 06
-id-input:modalias:input:b0003v28bdp0078*
+id-input:modalias:input:b0003v28bdp0078:*
  ID_INPUT_TABLET=1
 
 # Lite-On Tech IBM USB Travel Keyboard with Ultra Nav Mouse
-id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4*
+id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4*:*
  ID_INPUT_POINTINGSTICK=1
 
 # Logitech Ultrathin Touch Mouse
-id-input:modalias:input:b0005v046DpB00De0700*
+id-input:modalias:input:b0005v046DpB00De0700:*
  ID_INPUT_MOUSE=1
index 343f2cb7fddf8c6f0342469d0aa982cf729e4f25..97800f4364073b4c48329a1d6d4da722245651ea 100644 (file)
 # The lookup keys are composed in:
 #   60-evdev.rules
 #
-# Note: The format of the "evdev:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
+# Note: The format of the "evdev:" prefix match key is a contract between the
+# rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily expected to be a stable
+# ABI.
 #
 # Supported hardware matches are:
 #  - Generic input devices match:
@@ -47,7 +47,8 @@
 #    /sys/class/input/input?/capabilities/ev" and <vendor> is the
 #    firmware-provided string exported by the kernel DMI modalias,
 #    see /sys/class/dmi/id/modalias
-
+#
+# All matches should end in ':*' to allow future expansions of the match key.
 
 # ######################### KEY MAPPING ######################################
 #
 
 # A device with a fixed keyboard layout that must not be changed by
 # the desktop environment may specify that layout as:
-#   XKB_FIXED_LAYOUT="us"
-#   XKB_FIXED_VARIANT=""
+#   XKB_FIXED_LAYOUT=us
+#   XKB_FIXED_VARIANT=
 # Examples of such devices: the Yubikey or other key-code generating
 # devices.
 
 # A device where the scan code to key code mapping is insufficient and
 # requires a special key code to symbol configuration may specify that with:
-#   XKB_FIXED_MODEL="xkbmodel"
+#   XKB_FIXED_MODEL=xkbmodel
 # Examples of such devices: Chromebooks where the top row is used for both
 # media and F1-F10 keys.
 
 ##########################################
 
 # common keys
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGateway*:pnA0A1*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGateway*:pnA0A1*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:*
  KEYBOARD_KEY_86=wlan                                   # Fn+F3 or Fn+Q for comunication key
  KEYBOARD_KEY_a5=help                                   # Fn+F1
  KEYBOARD_KEY_a6=setup                                  # Fn+F2 Acer eSettings
@@ -133,17 +134,17 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr*
  KEYBOARD_KEY_f9=prog1                                  # Launch NTI shadow
 
 # Acer kernel driver
-evdev:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:pvr*
+evdev:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:*
  KEYBOARD_KEY_82=f21                                    # Touchpad toggle
 
 # Aspire models
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:*
  KEYBOARD_KEY_84=bluetooth                              # sent when bluetooth module missing, and key pressed
  KEYBOARD_KEY_d9=bluetooth                              # Bluetooth off
  KEYBOARD_KEY_92=media                                  # Acer arcade
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5720*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnZG8*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5720*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnZG8*:*
  KEYBOARD_KEY_f4=prog3                                  # e-key
 
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5920G:*
@@ -157,16 +158,16 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*8930:*
  KEYBOARD_KEY_89=fastforward
  KEYBOARD_KEY_9e=back
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*7750G:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*7750G:*
  KEYBOARD_KEY_e0=!pageup
 
 # Predator PH 315-52
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredator*PH*315-52:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredator*PH*315-52:*
  KEYBOARD_KEY_ef=kbdillumup                             # Fn+F10
  KEYBOARD_KEY_f0=kbdillumdown                           # Fn+F9
 
 # Travelmate C300
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:*
  KEYBOARD_KEY_67=f24                                    # FIXME: rotate screen
  KEYBOARD_KEY_68=up
  KEYBOARD_KEY_69=down
@@ -174,43 +175,41 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
  KEYBOARD_KEY_6c=screenlock                             # FIXME: lock tablet device/buttons
 
 # Travelmate P648-G2-MG, P648-G3-M and P645-S
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G2-MG*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G3-M*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P645-S*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G2-MG*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G3-M*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P645-S*:*
  KEYBOARD_KEY_8a=f20                                    # Microphone mute button; should be micmute
 
 # on some models this isn't brightnessup
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5220*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5610*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5620*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5720*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*4720*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5220*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5610*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5620*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5720*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*4720*:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*6593:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*1640:*
  KEYBOARD_KEY_ee=screenlock
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:*
  KEYBOARD_KEY_a9=!switchvideomode                       # Fn+F5
 
 # Packard Bell and Gateway models
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGateway*:pn*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPackard*Bell*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGateway*:pn*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPackard*Bell*:pn*:*
  KEYBOARD_KEY_86=wlan                                   # Fn+F3 or Fn+Q for comunication key
 
 ###########################################################
 # Alienware
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
+# Alienware/Dell reserves these keys; safe to apply on all their devices
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*:*
  KEYBOARD_KEY_81=f21                                    # Touchpad toggle
  KEYBOARD_KEY_8a=ejectcd
-
-# Alienware/Dell reserves these keys; safe to apply on all their devices
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*:pvr*
- KEYBOARD_KEY_bf=!prog1                                 #graphics amplifier, cable plug-in event
- KEYBOARD_KEY_c1=!prog2                                 #graphics amplifier, undock-button event
- KEYBOARD_KEY_c2=!power                                 #graphics amplifier, surprise undock event
+ KEYBOARD_KEY_bf=!prog1                                 # graphics amplifier, cable plug-in event
+ KEYBOARD_KEY_c1=!prog2                                 # graphics amplifier, undock-button event
+ KEYBOARD_KEY_c2=!power                                 # graphics amplifier, surprise undock event
 
 # Alienware M17xR3 laptops
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:*
@@ -220,32 +219,32 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:*
 # Asus
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnASUS:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnASUS:pn*:*
  KEYBOARD_KEY_ed=volumeup
  KEYBOARD_KEY_ee=volumedown
  KEYBOARD_KEY_ef=mute
 
-evdev:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
-evdev:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
-evdev:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
+evdev:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
+evdev:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
+evdev:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
  KEYBOARD_KEY_6b=f21                                    # Touchpad Toggle
 
 # USB keyboard in Asus FX503VD
-evdev:input:b0003v0B05p1869*
+evdev:input:b0003v0B05p1869:*
  KEYBOARD_KEY_ff31007c=f20                              # Remap micmute to f20
 
 ###########################################################
 # BenQ
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:*
  KEYBOARD_KEY_6e=wlan
 
 ###########################################################
 # Clevo
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNotebook:pnW65_67SZ:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNotebook:pnW65_67SZ:*
  KEYBOARD_KEY_a0=!mute
  KEYBOARD_KEY_a2=!playpause
  KEYBOARD_KEY_ae=!volumedown
@@ -262,14 +261,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCOMPAL:pnHEL80I:*
 # COMPAQ
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*E500*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*E500*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:*
  KEYBOARD_KEY_a3=www                                    # I key
  KEYBOARD_KEY_9a=search
  KEYBOARD_KEY_9e=email
  KEYBOARD_KEY_9f=homepage
 
-evdev:input:b0003v049Fp0051*
+evdev:input:b0003v049Fp0051:*
  KEYBOARD_KEY_0c0011=presentation
  KEYBOARD_KEY_0c0012=addressbook
  KEYBOARD_KEY_0c0013=info
@@ -288,7 +287,7 @@ evdev:name:gpio-keys:phys:gpio-keys/input0:ev:3:dmi:bvn*:bvr*:bd*:svncube:pni1-T
 # Dell
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*:*
  KEYBOARD_KEY_81=playpause                              # Play/Pause
  KEYBOARD_KEY_82=stopcd                                 # Stop
  KEYBOARD_KEY_83=previoussong                           # Previous song
@@ -320,69 +319,69 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*
  KEYBOARD_KEY_d9=f21                                    # Touchpad toggle
 
 #
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*101[012]:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*101[012]:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:*
  KEYBOARD_KEY_84=wlan
 
 # Dell Inspiron 1520 and Latitude 2110
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*2110:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*2110:*
  KEYBOARD_KEY_85=unknown  # Brightness Down, also emitted by acpi-video, ignore
  KEYBOARD_KEY_86=unknown  # Brightness Up, also emitted by acpi-video, ignore
 
 # Dell Inspiron 537*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron537*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron537*:*
  KEYBOARD_KEY_88=!wlan                                  # Fn-PrtScr rfkill
 
 # Latitude XT2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*XT2:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*XT2:*
  KEYBOARD_KEY_9b=up                                     # tablet rocker up
  KEYBOARD_KEY_9e=enter                                  # tablet rocker press
  KEYBOARD_KEY_9f=back                                   # tablet back
  KEYBOARD_KEY_a3=down                                   # tablet rocker down
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:*
  KEYBOARD_KEY_a0=!                                      # mute
  KEYBOARD_KEY_ae=!                                      # volume down
  KEYBOARD_KEY_b0=!                                      # volume up
 
 # Dell Touchpad
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:*
  KEYBOARD_KEY_88=!                                      # wireless switch
  KEYBOARD_KEY_9e=!f21
 
 # Dell Latitude E7*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E7*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E7*:*
  KEYBOARD_KEY_88=unknown                                # Fn-PrtScr rfkill - handled in HW
 
 # Dell XPS
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:*
  KEYBOARD_KEY_8c=!unknown
 
 # Dell XPS L702x
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDellInc.:pnDellSystemXPSL702X:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDellInc.:pnDellSystemXPSL702X:*
  KEYBOARD_KEY_84=prog1
  KEYBOARD_KEY_85=prog2
 
 # Dell XPS12 9Q33
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:*
  KEYBOARD_KEY_88=wlan
  KEYBOARD_KEY_65=direction                              # Screen Rotate
 
 # Dell Latitude microphone mute
-evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*
+evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:*
 # Dell Precision microphone mute
-evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*
+evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:*
  KEYBOARD_KEY_100150=f20                                   # Mic mute toggle, should be micmute
 
 ###########################################################
 # Everex
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:*
  KEYBOARD_KEY_5c=media
  KEYBOARD_KEY_65=f21                                    # Fn+F5 Touchpad toggle
  KEYBOARD_KEY_67=prog3                                  # Fan speed control button
@@ -395,7 +394,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr*
 # Fujitsu
 ##########################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*M*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*M*:*
  KEYBOARD_KEY_97=prog2
  KEYBOARD_KEY_9f=prog1
 
@@ -409,25 +408,25 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*Li*2732:*
  KEYBOARD_KEY_a9=switchvideomode                        # Fn+F10 Cycle between available video outputs
 
 # Amilo Pa 2548
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pa*2548*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pa*2548*:*
  KEYBOARD_KEY_e0=volumedown
  KEYBOARD_KEY_e1=volumeup
  KEYBOARD_KEY_e5=prog1
 
 # Amilo Pro Edition V3505
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:*
  KEYBOARD_KEY_a5=help                                   # Fn+F1
  KEYBOARD_KEY_a9=switchvideomode                        # Fn+F3
  KEYBOARD_KEY_d9=brightnessdown                         # Fn+F8
  KEYBOARD_KEY_e0=brightnessup                           # Fn+F9
 
 # Amilo Pro v3205
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:*
  KEYBOARD_KEY_f4=f21                                    # FIXME: silent-mode decrease CPU/GPU clock
  KEYBOARD_KEY_f7=switchvideomode                        # Fn+F3
 
 # Amilo Si 1520
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:*
  KEYBOARD_KEY_e1=wlan
  KEYBOARD_KEY_f3=wlan
  KEYBOARD_KEY_ee=brightnessdown
@@ -436,14 +435,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr*
  KEYBOARD_KEY_f7=video
 
 # Esprimo Mobile V5
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V5*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V5*:*
  KEYBOARD_KEY_a9=switchvideomode
  KEYBOARD_KEY_d9=brightnessdown
  KEYBOARD_KEY_df=sleep
  KEYBOARD_KEY_ef=brightnessup
 
 # Esprimo Mobile V6
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:*
  KEYBOARD_KEY_ce=brightnessup
  KEYBOARD_KEY_ef=brightnessdown
 
@@ -466,7 +465,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGeminiDevices:pnNC14V1006:*
 ###########################################################
 
 # Slimstar 320
-evdev:input:b0003v0458p0708*
+evdev:input:b0003v0458p0708:*
  KEYBOARD_KEY_0900f0=scrollup
  KEYBOARD_KEY_0900f1=scrolldown
  KEYBOARD_KEY_0900f3=back
@@ -486,11 +485,11 @@ evdev:input:b0003v0458p0708*
 # Hewlett Packard
 ###########################################################
 
-evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pn*:pvr*
+evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
  KEYBOARD_KEY_8=unknown                                        # Use hp-wireless instead
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
  KEYBOARD_KEY_81=fn_esc
  KEYBOARD_KEY_89=battery                                # Fn+F8
  KEYBOARD_KEY_8a=screenlock                             # Fn+F6
@@ -505,7 +504,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:pvr*
  KEYBOARD_KEY_ee=switchvideomode                        # Fn+F4
 
 # Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:*
  KEYBOARD_KEY_82=prog2                                  # Funny Key
  KEYBOARD_KEY_83=prog1                                  # Q
  KEYBOARD_KEY_84=tab
@@ -514,31 +513,31 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:p
  KEYBOARD_KEY_87=pagedown
 
 # Pavilion
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:*
  KEYBOARD_KEY_88=media                                  # FIXME: quick play
  KEYBOARD_KEY_b7=print
  KEYBOARD_KEY_d8=!f23                                   # touchpad off
  KEYBOARD_KEY_d9=!f22                                   # touchpad on
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:*
  KEYBOARD_KEY_b7=print
  KEYBOARD_KEY_c2=media                                  # FIXME: quick play
  KEYBOARD_KEY_c6=break
  KEYBOARD_KEY_94=reserved
 
 # Pavilion 13 x360 (Tablet mode and SYSRQ key)
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:*
  KEYBOARD_KEY_d7=!f22                                   # touchpad off
  KEYBOARD_KEY_d9=unknown
  KEYBOARD_KEY_d2=sysrq                                  # Fn+Print = SYSRQ
 
 # Spectre x360 13 (Prevents random airplane mode activation)
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360*13*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convertible*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360*13*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convertible*:*
  KEYBOARD_KEY_d7=unknown
 
 # Spectre x360 13
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:*
  KEYBOARD_KEY_82=f20                                    # Fn+F12; Microphone mute button, should be micmute
 
 # HP Elite x2 1013 G3
@@ -554,42 +553,42 @@ evdev:name:Intel HID events:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:*
   KEYBOARD_KEY_08=unknown                               # rfkill is also reported by HP Wireless hotkeys
 
 # Elitebook
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:*
  KEYBOARD_KEY_88=presentation
  KEYBOARD_KEY_d9=help                                   # I key (high keycode: "info")
 
 # Presario
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:*
  KEYBOARD_KEY_d8=f21
  KEYBOARD_KEY_d9=f21
 
 # 2510p 2530p
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:*
  KEYBOARD_KEY_d8=!f23                                   # touchpad off
  KEYBOARD_KEY_d9=!f22                                   # touchpad on
 
 # 2570p
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:*
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
 # TX2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:*
  KEYBOARD_KEY_c2=media
  KEYBOARD_KEY_d8=!f23                                   # Toggle touchpad button on tx2 (OFF)
  KEYBOARD_KEY_d9=!f22                                   # Toggle touchpad button on tx2 (ON)
 
 # Presario 2100
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:*
  KEYBOARD_KEY_f0=help
  KEYBOARD_KEY_f1=screenlock
  KEYBOARD_KEY_f3=search
 
 # Elitebook 8440p
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:*
  KEYBOARD_KEY_88=www
  KEYBOARD_KEY_a0=mute
  KEYBOARD_KEY_ae=volumedown
@@ -597,53 +596,58 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr*
  KEYBOARD_KEY_ec=mail
 
 # Elitebook 8460p
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:*
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
  KEYBOARD_KEY_b3=prog1                                  # Fn+F11 - Ambient Light Sensor button
  KEYBOARD_KEY_b1=prog2                                  # Fn+ESC - System information button
 
 # HDX9494nr
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:*
  KEYBOARD_KEY_b2=www                                    # Fn+F3
  KEYBOARD_KEY_d8=!f23                                   # touchpad off
  KEYBOARD_KEY_d9=!f22                                   # touchpad on
 
 # HP EliteBook 725 G2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:*
 # HP EliteBook
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBook*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteBook*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBook*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteBook*:*
 # HP ProBook 440 G2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:*
 # several HP ProBooks 4xx
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*ProBook4*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHP*ProBook*4*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*ProBook4*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHP*ProBook*4*:*
 # HP ZBook
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPZBook*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPZBook*:*
  KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
 
 # HP ZBook 15 G2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook15G2:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook15G2:*
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
 # HP ProBook 11 G1
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook11G1:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook11G1:*
  KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
  KEYBOARD_KEY_d8=f21                                    # touchpad toggle
  KEYBOARD_KEY_d9=f21                                    # touchpad toggle
 
 # HP ZBook Studio G4
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPZBookStudioG4:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPZBookStudioG4:*
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
-# HP Folio 1040g2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:pvr*
+# HP EliteBook Folio 1040 G2
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:*
  KEYBOARD_KEY_d8=!f23                                   # touchpad off
  KEYBOARD_KEY_d9=!f22                                   # touchpad on
 
+# HP EliteBook Folio G1
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteBookFolioG1:*
+ KEYBOARD_KEY_64=calendar
+ KEYBOARD_KEY_81=micmute
+
 # HP ProBook 650
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*ProBook*650*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*ProBook*650*:*
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
 # HP ProBook 6555b
@@ -651,14 +655,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:*
  KEYBOARD_KEY_b2=www                                    # Earth
 
 # HP ProBook 440 G3
-evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*440*G3*
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*440*G3*:*
 # HP ProBook 640 G2
-evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*640*G2*
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*640*G2*:*
  KEYBOARD_KEY_85=unknown                                # lid close; also reported via special evdev
  KEYBOARD_KEY_f8=unknown                                # rf kill; also reported via special evdev
 
 # HP ProBook 645 G4
-evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*645*G4*
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*645*G4*:*
  KEYBOARD_KEY_73=slash                                  # Slash key
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
@@ -675,15 +679,15 @@ evdev:name:gpio-keys:phys:gpio-keys/input0:ev:23:dmi:*:svnHewlett-Packard:pnHPSt
 ##########################################################
 
 # Huawei WMI hotkeys driver
-evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*
+evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI:*
  KEYBOARD_KEY_287=f20                                   # Microphone mute button, should be micmute
 
 # Huawei MACH-WX9
-evdev:atkbd:dmi:bvn*:bvr*:svnHUAWEI*:pnMACH-WX9:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:svnHUAWEI*:pnMACH-WX9:*
  KEYBOARD_KEY_f7=unknown
  KEYBOARD_KEY_f8=fn
 
-evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*:pnMACH-WX9:pvr*
+evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*:pnMACH-WX9:*
  KEYBOARD_KEY_281=unknown                               # Brightness Down, also emitted by acpi-video, ignore
  KEYBOARD_KEY_282=unknown                               # Brightness Up, also emitted by acpi-video, ignore
 
@@ -692,7 +696,7 @@ evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*:pnMACH-WX9:pvr*
 ###########################################################
 
 # thinkpad_acpi driver
-evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr*
+evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:*
  KEYBOARD_KEY_01=battery                                # Fn+F2
  KEYBOARD_KEY_02=screenlock                             # Fn+F3
  KEYBOARD_KEY_03=sleep                                  # Fn+F4
@@ -711,7 +715,7 @@ evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr*
  KEYBOARD_KEY_17=prog1                                  # ThinkPad/ThinkVantage button (high keycode: "vendor")
 
 # IBM Thinkpad USB Keyboard Trackpoint
-evdev:input:b0003v04B3p301[89]*
+evdev:input:b0003v04B3p301[89]:*
  KEYBOARD_KEY_900f0=screenlock
  KEYBOARD_KEY_900f1=wlan
  KEYBOARD_KEY_900f2=switchvideomode
@@ -725,7 +729,7 @@ evdev:input:b0003v04B3p301[89]*
 ###########################################################
 
 # Symphony
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:*
  KEYBOARD_KEY_f3=prog2
  KEYBOARD_KEY_f4=prog1
 
@@ -734,7 +738,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr*
 ###########################################################
 
 # thinkpad_acpi driver
-evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
+evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
  KEYBOARD_KEY_01=screenlock
  KEYBOARD_KEY_02=battery
  KEYBOARD_KEY_03=sleep
@@ -755,7 +759,7 @@ evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
  KEYBOARD_KEY_45=bookmarks
 
 # ThinkPad Keyboard with TrackPoint
-evdev:input:b0003v17EFp6009*
+evdev:input:b0003v17EFp6009:*
  KEYBOARD_KEY_090012=screenlock                         # Fn+F2
  KEYBOARD_KEY_090013=battery                            # Fn+F3
  KEYBOARD_KEY_090014=wlan                               # Fn+F5
@@ -770,7 +774,7 @@ evdev:input:b0003v17EFp6009*
  KEYBOARD_KEY_090010=f20                                # Microphone mute button; should be micmute
 
 # Lenovo 3000
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:*
  KEYBOARD_KEY_8b=switchvideomode                        # Fn+F7 video
  KEYBOARD_KEY_96=wlan                                   # Fn+F5 wireless
  KEYBOARD_KEY_97=sleep                                  # Fn+F4 suspend
@@ -782,8 +786,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn0769AP2:pvr3000N200:*
  KEYBOARD_KEY_b4=prog1
 
 # lenovo-ideapad
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:*
  KEYBOARD_KEY_81=rfkill                                 # does nothing in BIOS
  KEYBOARD_KEY_83=display_off                            # BIOS toggles screen state
  KEYBOARD_KEY_b9=brightnessup                           # does nothing in BIOS
@@ -793,7 +797,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr*
  KEYBOARD_KEY_f3=f21
 
 # Thinkpad X200_Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*:*
  KEYBOARD_KEY_5d=menu
  KEYBOARD_KEY_63=fn
  KEYBOARD_KEY_66=screenlock
@@ -802,7 +806,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*
  KEYBOARD_KEY_6c=direction                              # rotate screen
 
 # ThinkPad X6 Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:*
  KEYBOARD_KEY_6c=direction                              # rotate
  KEYBOARD_KEY_68=leftmeta                               # toolbox
  KEYBOARD_KEY_6b=esc                                    # escape
@@ -813,28 +817,28 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*
  KEYBOARD_KEY_69=enter                                  # enter on d-pad
 
 # ThinkPad X41 Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:*
  KEYBOARD_KEY_6c=direction                              # rotate
  KEYBOARD_KEY_68=leftmeta                               # toolbox
  KEYBOARD_KEY_6b=esc                                    # escape
  KEYBOARD_KEY_69=enter                                  # enter on d-pad
 
 # IdeaPad
-evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
+evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
  KEYBOARD_KEY_0d=rfkill                                 # airplane mode switch (toggle all wireless devices)
  KEYBOARD_KEY_08=f20                                    # micmute
  KEYBOARD_KEY_42=f23
  KEYBOARD_KEY_43=f22
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:*
  KEYBOARD_KEY_95=media
  KEYBOARD_KEY_a3=play
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:*
  KEYBOARD_KEY_f1=f21
  KEYBOARD_KEY_ce=f20                                    # micmute
 
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:*
  KEYBOARD_KEY_a0=!mute
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
@@ -843,26 +847,26 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
 # For 10th gen it should be pn81Q8 instead of pn81Q7 but
 # I don't have a device to test
 # perhaps pn81Q* would work for both generations
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO:pn81Q7*:pvrLenovoYogaS940*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO:pn81Q7*:pvrLenovoYogaS940:*
  KEYBOARD_KEY_a0=!mute
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
 
 # Lenovo Y50-70
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:*
  KEYBOARD_KEY_f3=f21      # Fn+F6 (toggle touchpad)
 
 # V480
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:*
  KEYBOARD_KEY_f1=f21
 
 # Lenovo ThinkCentre M800z/M820z/M920z AIO machines
 # key_scancode 00 is KEY_MICMUTE
-evdev:name:Microphone Mute Button:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
+evdev:name:Microphone Mute Button:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
  KEYBOARD_KEY_00=f20
 
 # enhanced USB keyboard
-evdev:input:b0003v04B3p301B*
+evdev:input:b0003v04B3p301B:*
  KEYBOARD_KEY_90001=prog1 # ThinkVantage
  KEYBOARD_KEY_90002=screenlock
  KEYBOARD_KEY_90003=file
@@ -880,7 +884,7 @@ evdev:input:b0003v04B3p301B*
 # 27MHz wireless keyboards, these all have a PID of 00?? and all send c10xx
 # logitech custom consumer usage-page codes. The mappings below are the most
 # common, but some mapping may differ, especially the Fn F1-F12 mappings
-evdev:input:b0003v046Dp00*
+evdev:input:b0003v046Dp00??:*
  KEYBOARD_KEY_c0183=media           # HUT:config, kbd:Media/Music player button
  KEYBOARD_KEY_c1001=chat            # Messenger button
  KEYBOARD_KEY_c1002=camera          # Webcam button
@@ -930,7 +934,7 @@ evdev:input:b0003v046Dp00*
  KEYBOARD_KEY_c104c=prog4           # Smartkey D (Fn + F12) → XF86Launch4
 
 # Cordless Access Keyboard (27 MHz, modelnumber Y-RH35)
-evdev:input:b0003v046Dp0042*
+evdev:input:b0003v046Dp0042:*
  KEYBOARD_KEY_c1041=new
  KEYBOARD_KEY_c1042=reply
  KEYBOARD_KEY_c1043=forward
@@ -945,7 +949,7 @@ evdev:input:b0003v046Dp0042*
  KEYBOARD_KEY_c104c=audio
 
 # "Cordless Rechargeable Desktop" keyboard (27 MHz, modelnumber Y-RK49)
-evdev:input:b0003v046Dp0045*
+evdev:input:b0003v046Dp0045:*
  KEYBOARD_KEY_c1041=new
  KEYBOARD_KEY_c1042=reply
  KEYBOARD_KEY_c1043=forward
@@ -956,7 +960,7 @@ evdev:input:b0003v046Dp0045*
  KEYBOARD_KEY_c104c=audio
 
 # S510 keyboard (27 MHz, modelnumber Y-RAK73)
-evdev:input:b0003v046Dp0056*
+evdev:input:b0003v046Dp0056:*
  KEYBOARD_KEY_c1041=battery      # Battery icon (Fn + F1)
 
 # MX3000 keyboard (27 MHz, modelnumber Y-RAM74)
@@ -965,7 +969,7 @@ evdev:input:b0003v046Dp0056*
 # Note if the "Special Button Function" in the HID++ features register gets
 # cleared then the scroll-wheel events for these buttons go away and then
 # tilting the scrollwheel left/right starts sending c1022 / c1024 events
-evdev:input:b0003v046Dp0057*
+evdev:input:b0003v046Dp0057:*
  KEYBOARD_KEY_c1041=battery      # Battery icon (Fn + F1)
 
 #KEYBOARD_KEY_c101d=scrolldown   # Button below scrollwheel (see note above)
@@ -974,7 +978,7 @@ evdev:input:b0003v046Dp0057*
 #KEYBOARD_KEY_c1024=scrollright  # Right click on scroll-wheel (see note above)
 
 # MX3200 keyboard (27 MHz, modelnumber Y-RAV80)
-evdev:input:b0003v046Dp005C*
+evdev:input:b0003v046Dp005C:*
  KEYBOARD_KEY_c1001=phone           # VOIP button
  KEYBOARD_KEY_c1016=record          # Record button
  KEYBOARD_KEY_c1041=wordprocessor   # Word icon (Fn + F1)
@@ -987,13 +991,13 @@ evdev:input:b0003v046Dp005C*
  KEYBOARD_KEY_c1048=prog4           # Smartkey D (Fn + F8) → XF86Launch4
 
 # EX100 keyboard (27 MHz, modelnumber Y-RBH94)
-evdev:input:b0003v046Dp0065*
+evdev:input:b0003v046Dp0065:*
  KEYBOARD_KEY_c104b=battery         # Battery icon (Fn + F11)
  KEYBOARD_KEY_c104c=ejectcd         # Eject icon (Fn + F12)
 
 # S520 keyboard (27 MHz, modelnumber Y-RBA97)
 # Note this one uses non-standard codes for FN + F9 - Fn + F12?
-evdev:input:b0003v046Dp0066*
+evdev:input:b0003v046Dp0066:*
  KEYBOARD_KEY_c100e=prog4           # Smartkey D (Fn + F12) → XF86Launch4
  KEYBOARD_KEY_c1019=prog1           # Smartkey A (Fn + F9)  → XF86Launch1
  KEYBOARD_KEY_c101a=prog2           # Smartkey B (Fn + F10) → XF86Launch2
@@ -1009,12 +1013,12 @@ evdev:input:b0003v046Dp0066*
  KEYBOARD_KEY_c106f=battery         # Battery icon
 
 # S510 remote control (27 MHz)
-evdev:input:b0003v046Dp00FE*
+evdev:input:b0003v046Dp00FE:*
  KEYBOARD_KEY_c1018=media           # Media button
 
 # MX5000 keyboard (HID proxy mode and bluetooth matches)
-evdev:input:b0003v046DpB305*
-evdev:input:b0005v046DpB305*
+evdev:input:b0003v046DpB305:*
+evdev:input:b0005v046DpB305:*
  KEYBOARD_KEY_c0230=zoomreset  # HUT says fullscreen, kbd says 100%
  KEYBOARD_KEY_c1004=send       # Send and receive / sync button
  KEYBOARD_KEY_c1006=coffee     # Status (online/away) button
@@ -1029,8 +1033,8 @@ evdev:input:b0005v046DpB305*
  KEYBOARD_KEY_c103b=prog4      # Smartkey D → XF86Launch4
 
 # MX5500 keyboard (HID proxy mode and bluetooth matches)
-evdev:input:b0003v046DpB30B*
-evdev:input:b0005v046DpB30B*
+evdev:input:b0003v046DpB30B:*
+evdev:input:b0005v046DpB30B:*
  KEYBOARD_KEY_c0183=media      # HUT says consumer control configuration, kbd says Media Center
  KEYBOARD_KEY_c100e=images      # Camera icon, "Photo Gallery"
  KEYBOARD_KEY_c100f=config      # Window with gear icon
@@ -1040,12 +1044,12 @@ evdev:input:b0005v046DpB30B*
  KEYBOARD_KEY_c103b=prog4      # Smartkey D → XF86Launch4
 
 # Logitech K811
-evdev:input:b0005v046DpB317*
+evdev:input:b0005v046DpB317:*
  KEYBOARD_KEY_70047=brightnessdown
  KEYBOARD_KEY_70048=brightnessup
 
 # iTouch
-evdev:input:b0003v046DpC308*
+evdev:input:b0003v046DpC308:*
  KEYBOARD_KEY_90001=shop                                # Shopping
  KEYBOARD_KEY_90002=config                              # iTouch
  KEYBOARD_KEY_90003=finance                             # Finance
@@ -1054,12 +1058,12 @@ evdev:input:b0003v046DpC308*
  KEYBOARD_KEY_c0183=media                               # Media
 
 # Cordless Desktop S510
-evdev:input:b0003v046DpC50C*
+evdev:input:b0003v046DpC50C:*
  KEYBOARD_KEY_d4=up                                     # zoomin
  KEYBOARD_KEY_cc=down                                   # zoomout
 
 # Wave cordless
-evdev:input:b0003v046DpC317*
+evdev:input:b0003v046DpC317:*
  KEYBOARD_KEY_9001c=scale                               # expo
  KEYBOARD_KEY_9001f=down                                # zoomout
  KEYBOARD_KEY_90020=up                                  # zoomin
@@ -1078,7 +1082,7 @@ evdev:input:b0003v046DpC317*
  KEYBOARD_KEY_9004c=ejectclosecd
 
 # Wave cordless
-evdev:input:b0003v046DpC517*
+evdev:input:b0003v046DpC517:*
  KEYBOARD_KEY_c101f=down                                # zoomout
  KEYBOARD_KEY_c1020=up                                  # zoomin
  KEYBOARD_KEY_c1005=camera
@@ -1094,7 +1098,7 @@ evdev:input:b0003v046DpC517*
  KEYBOARD_KEY_c104c=ejectclosecd
 
 # Cordless Wave Pro
-evdev:input:b0003v046DpC529*
+evdev:input:b0003v046DpC529:*
  KEYBOARD_KEY_0c01b6=camera
  KEYBOARD_KEY_0c0183=media
  KEYBOARD_KEY_0c0184=wordprocessor
@@ -1109,13 +1113,13 @@ evdev:input:b0003v046DpC529*
  KEYBOARD_KEY_0c022e=down                               # zoomout
 
 # Logitech Presenter R400
-evdev:input:b0003v046DpC52D*
+evdev:input:b0003v046DpC52D:*
  KEYBOARD_KEY_070029=presentation
  KEYBOARD_KEY_07003e=presentation
  KEYBOARD_KEY_070037=displaytoggle
 
 # Internet Navigator
-evdev:input:b0003v046DpC309*
+evdev:input:b0003v046DpC309:*
  KEYBOARD_KEY_90001=chat         # Messenger/SMS
  KEYBOARD_KEY_90002=camera       # webcam
  KEYBOARD_KEY_90003=prog1        # iTouch
@@ -1139,7 +1143,7 @@ evdev:input:b0003v046DpC309*
 ###########################################################
 
 # Pro 7000
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:*
  KEYBOARD_KEY_97=prog2
  KEYBOARD_KEY_9f=prog1
  KEYBOARD_KEY_a0=mute                                   # Fn+F5
@@ -1155,9 +1159,9 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
 ###########################################################
 
 # Akoya
-evdev:atkbd:dmi:bvn*:bvr*:svnMEDION*:pnS3409*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnAkoya*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnP6669*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:svnMEDION*:pnS3409*:*
+evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnAkoya*:*
+evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnP6669*:*
  KEYBOARD_KEY_a0=!mute
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
@@ -1165,19 +1169,19 @@ evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnP6669*:pvr*
  KEYBOARD_KEY_df=sleep
 
 # FID2060
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:*
  KEYBOARD_KEY_6b=channeldown                            # Thottle Down
  KEYBOARD_KEY_6d=channelup                              # Thottle Up
 
 # NB-A555
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:*
  KEYBOARD_KEY_63=www                                    # N button
  KEYBOARD_KEY_66=prog1                                  # link 1 button
  KEYBOARD_KEY_67=email                                  # envelope button
  KEYBOARD_KEY_69=prog2                                  # link 2 button
 
 # Erazer
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMedion*:pnErazer*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMedion*:pnErazer*:*
  KEYBOARD_KEY_a0=!mute
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
@@ -1187,12 +1191,12 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMedion*:pnErazer*:pvr*
 ###########################################################
 
 # Microsoft Natural Ergonomic Keyboard 4000
-evdev:input:b0003v045Ep00DB*
+evdev:input:b0003v045Ep00DB:*
  KEYBOARD_KEY_c022d=up                                  # zoomin
  KEYBOARD_KEY_c022e=down                                # zoomout
 
 # Microsoft (Razer produced) Reclusa keyboard
-evdev:input:b0003v1532p0200*
+evdev:input:b0003v1532p0200:*
  KEYBOARD_KEY_c01c9=shuffle
  KEYBOARD_KEY_c01ca=up                                  # zoomin
  KEYBOARD_KEY_c01cb=down                                # zoomout
@@ -1201,12 +1205,13 @@ evdev:input:b0003v1532p0200*
 # Micro Star
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:*
  KEYBOARD_KEY_a0=mute                                   # Fn+F9
  KEYBOARD_KEY_ae=volumedown                             # Fn+F7
  KEYBOARD_KEY_b0=volumeup                               # Fn+F8
  KEYBOARD_KEY_b2=www                                    # e button
+ KEYBOARD_KEY_c2=ejectcd
  KEYBOARD_KEY_df=sleep                                  # Fn+F12
  KEYBOARD_KEY_e2=bluetooth                              # satellite dish2
  KEYBOARD_KEY_e4=f21                                    # Fn+F3 Touchpad disable
@@ -1217,20 +1222,18 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*
  KEYBOARD_KEY_f8=brightnessup                           # Fn+F5
  KEYBOARD_KEY_f9=search
 
-#
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE60*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE70*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE60*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE70*:*
  KEYBOARD_KEY_c2=ejectcd
 
 # some MSI models generate ACPI/input events on the LNXVIDEO input devices,
 # plus some extra synthesized ones on atkbd as an echo of actually changing the
 # brightness; so ignore those atkbd ones, to avoid loops
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U-100*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U100*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U-100*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U100*:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*N033:*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*VR420*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*PR200*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*VR420*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*PR200*:*
  KEYBOARD_KEY_f7=reserved
  KEYBOARD_KEY_f8=reserved
 
@@ -1239,7 +1242,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:*
  KEYBOARD_KEY_e4=reserved
 
 # MSI Prestige15 A10SC specific keycodes. Needed for microphone and screen rotation
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:*
  KEYBOARD_KEY_f1=f20
  KEYBOARD_KEY_f2=f21
 
@@ -1247,7 +1250,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:pvr*
 # MSI
 ###########################################################
 
-evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:pvr*
+evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:*
  KEYBOARD_KEY_0213=f22
  KEYBOARD_KEY_0214=f23
 
@@ -1256,7 +1259,7 @@ evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][a
 ###########################################################
 
 # Teres-I
-evdev:input:b0003v15BAp003C*
+evdev:input:b0003v15BAp003C:*
  KEYBOARD_KEY_70066=sleep                               # Fn+F1
  KEYBOARD_KEY_700f6=wlan                                # Fn+F2
  KEYBOARD_KEY_700c7=f21                                 # Fn+F3 touchpad toggle
@@ -1353,7 +1356,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:*
 ###########################################################
 
 # Model 2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:*
  KEYBOARD_KEY_8e=wlan
  KEYBOARD_KEY_f0=switchvideomode
  KEYBOARD_KEY_f1=mute
@@ -1368,7 +1371,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr*
 # The key code identifiers used below exactly match the text
 # labels on the keys/buttons (or standard icons on the buttons
 # that have no text labels), except as noted.
-evdev:input:b0003v05A4p9735*
+evdev:input:b0003v05A4p9735:*
  KEYBOARD_KEY_c0015=back
  KEYBOARD_KEY_c0012=forward
  KEYBOARD_KEY_c000c=stop
@@ -1399,7 +1402,7 @@ evdev:input:b0003v05A4p9735*
 ###########################################################
 
 # Plantronics .Audio 626 DSP
-evdev:input:b0003v047FpC006*
+evdev:input:b0003v047FpC006:*
  KEYBOARD_KEY_b002f=f20                                # Microphone mute button; should be micmute
 
 ###########################################################
@@ -1407,15 +1410,15 @@ evdev:input:b0003v047FpC006*
 ###########################################################
 
 # Purism Librem 13 V2
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v2*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v2*:*
  KEYBOARD_KEY_56=backslash
 
 # Purism Librem 13 V3
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v3*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v3*:*
  KEYBOARD_KEY_56=backslash
 
 # Purism Librem 13 V4
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v4*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v4*:*
  KEYBOARD_KEY_56=backslash
 
 ###########################################################
@@ -1429,7 +1432,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*:rvnQuanta:rn30B7:rvr65.2B:*
 # Samsung
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*:*
  KEYBOARD_KEY_74=prog1                                  # User key
  KEYBOARD_KEY_75=www
  KEYBOARD_KEY_78=mail
@@ -1448,28 +1451,28 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*
  KEYBOARD_KEY_f9=!f23                                   # Fn+F10 Touchpad off
 
 # Series 3
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:*
  KEYBOARD_KEY_ce=!                                      # Fn+F1  launch control setting
 
 # Series 5
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_a8=!                                      # Fn Lock - Function lock on
  KEYBOARD_KEY_a9=!                                      # Fn Lock - Function lock off
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_a8=!                                      # Fn Lock - Function lock on
  KEYBOARD_KEY_a9=!                                      # Fn Lock - Function lock off
 
 # Series 7 / 9
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*350V*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*670Z*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34]*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*350V*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*670Z*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34]*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_a0=!mute                                  # Fn+F6 mute
  KEYBOARD_KEY_ae=!volumedown                            # Fn+F7
@@ -1478,14 +1481,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr*
  KEYBOARD_KEY_96=!kbdillumup                            # Fn+F10 keyboard backlight up
  KEYBOARD_KEY_b3=!prog3                                 # Fn+F11 fan/cooling mode changer
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:*
  KEYBOARD_KEY_ce=!                                      # Fn+F8 keyboard backlight up
  KEYBOARD_KEY_8d=!                                      # Fn+F7 keyboard backlight down
  KEYBOARD_KEY_96=!                                      # Fn+F1 performance mode (?)
  KEYBOARD_KEY_97=!                                      # Fn+F12 Wi-Fi toggle
  KEYBOARD_KEY_d5=!                                      # Fn+F6 battery life extender
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_8d=!prog3                                 # Fn+F6 performance mode
  KEYBOARD_KEY_97=!kbdillumdown                          # Fn+F7 keyboard backlight down
@@ -1493,7 +1496,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr*
  KEYBOARD_KEY_d5=!wlan                                  # Fn+F12 Wi-Fi toggle
 
 # Series 7 Ultra
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*7[34]0U3E*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*7[34]0U3E*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_97=!kbdillumdown                          # Fn+F9 keyboard backlight down
  KEYBOARD_KEY_96=!kbdillumup                            # Fn+F10 keyboard backlight up
@@ -1501,13 +1504,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*7[34]0U3E*:pvr
  KEYBOARD_KEY_d5=!wlan                                  # Fn+F12 wlan/airplane switch
 
 # ATIV Book 6 / 8
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*[68][78]0Z*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*[68][78]0Z*:*
  KEYBOARD_KEY_ce=!prog1                                 # Fn+F1 launch settings
  KEYBOARD_KEY_96=!kbdillumup                            # Fn+F10 keyboard backlight up
  KEYBOARD_KEY_97=!kbdillumdown                          # Fn+F9 keyboard backlight down
 
 # SQ1US
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:*
  KEYBOARD_KEY_d4=menu
  KEYBOARD_KEY_d8=f1
  KEYBOARD_KEY_d9=f10
@@ -1517,13 +1520,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr*
  KEYBOARD_KEY_ee=f11
 
 # SX20S
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:*
  KEYBOARD_KEY_74=mute
  KEYBOARD_KEY_75=mute
  KEYBOARD_KEY_77=f22                                    # Touchpad on
  KEYBOARD_KEY_79=f23                                    # Touchpad off
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:*
  KEYBOARD_KEY_ad=leftmeta
 
 ###########################################################
@@ -1531,7 +1534,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr*
 ###########################################################
 
 # sony-laptop driver
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*:*
  KEYBOARD_KEY_06=mute                                   # Fn+F2
  KEYBOARD_KEY_07=volumedown                             # Fn+F3
  KEYBOARD_KEY_08=volumeup                               # Fn+F4
@@ -1541,22 +1544,22 @@ evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*
  KEYBOARD_KEY_0e=zoom                                   # Fn+F10
  KEYBOARD_KEY_10=suspend                                # Fn+F12
 
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-C1*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-K25*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-F[1-6]*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FX*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FRV*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-GR*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-TR*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-NV*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-Z*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*VGN-S360*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-C1*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-K25*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-F[1-6]*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FX*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FRV*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-GR*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-TR*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-NV*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-Z*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*VGN-S360*:*
  KEYBOARD_KEY_06=battery
  KEYBOARD_KEY_07=mute
 
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-AR71*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW*:pvr*
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-AR71*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW*:*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:*
  KEYBOARD_KEY_00=brightnessdown                         # Fn+F5
  KEYBOARD_KEY_10=brightnessup                           # Fn+F6
  KEYBOARD_KEY_11=switchvideomode                        # Fn+F7
@@ -1566,10 +1569,10 @@ evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr*
  KEYBOARD_KEY_17=prog1
  KEYBOARD_KEY_20=media
 
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:*
  KEYBOARD_KEY_10=suspend                                # Fn+F12
 
-evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:*
  KEYBOARD_KEY_05=f21                                    # Fn+F1 -> KEY_F21 (The actual touchpad toggle)
  KEYBOARD_KEY_0d=down                                   # Fn+F9 zoomout
  KEYBOARD_KEY_0e=up                                     # Fn+F10 zoomin
@@ -1578,7 +1581,7 @@ evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr*
 # System76
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pn*:*
  KEYBOARD_KEY_f7=f21                                    # Touchpad toggle
  KEYBOARD_KEY_f8=f21                                    # Touchpad toggle
 
@@ -1586,7 +1589,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pn*
 # T-bao
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnT-bao:pnTbookair:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnT-bao:pnTbookair:*
  KEYBOARD_KEY_76=f21                                    # Touchpad toggle
 
 ###########################################################
@@ -1594,12 +1597,12 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnT-bao:pnTbookair:pvr*
 ###########################################################
 
 # Satellite A100
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITE*A100:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITE*A100:*
  KEYBOARD_KEY_a4=stopcd
  KEYBOARD_KEY_b2=www
 
 # Satellite A110
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:*
  KEYBOARD_KEY_92=stop
  KEYBOARD_KEY_93=www
  KEYBOARD_KEY_94=media
@@ -1612,7 +1615,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr*
  KEYBOARD_KEY_f7=playpause
 
 # Satellite M30X
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:*
  KEYBOARD_KEY_ef=brightnessdown
  KEYBOARD_KEY_d9=brightnessup
  KEYBOARD_KEY_ee=screenlock
@@ -1621,21 +1624,21 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr*
  KEYBOARD_KEY_9f=f23                                    # touchpad disable
 
 # Satellite P75-A
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:*
  KEYBOARD_KEY_ef=brightnessdown
  KEYBOARD_KEY_ee=brightnessup
  KEYBOARD_KEY_a9=switchvideomode                        # switch display outputs
  KEYBOARD_KEY_d4=wlan                                   # RF Switch Off
 
 # Satellite U940
-evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:pvr*
+evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:*
  KEYBOARD_KEY_13c=brightnessdown
  KEYBOARD_KEY_13d=brightnessup
  KEYBOARD_KEY_13e=switchvideomode
  KEYBOARD_KEY_13f=f21                                   # Touchpad toggle
 
 # Satellite P75-A7200
-evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
+evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:*
  KEYBOARD_KEY_13c=brightnessdown
  KEYBOARD_KEY_13d=brightnessup
  KEYBOARD_KEY_13e=switchvideomode
@@ -1646,14 +1649,14 @@ evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:
 # VIA
 ###########################################################
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:*
  KEYBOARD_KEY_81=prog1
 
 ###########################################################
 # VIOS
 ###########################################################
 
-evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:bd*:svnVIOS:pnLTH17:pvr*
+evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:bd*:svnVIOS:pnLTH17:*
  KEYBOARD_KEY_70073=f21                                 # Touchpad toggle
 
 ###########################################################
@@ -1661,7 +1664,7 @@ evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:bd*:svnVIOS:pnLTH17:pvr*
 ###########################################################
 
 # P325J
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINET:pnP325J:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINET:pnP325J:*
  KEYBOARD_KEY_76=f21                                    # Touchpad toggle
 
 ###########################################################
@@ -1696,7 +1699,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote*6615WD:*
 ##########################################
 
 # Ideazon Zboard Merc
-evdev:input:b0003v1038p0210*
+evdev:input:b0003v1038p0210:*
  KEYBOARD_KEY_c0227=q
  KEYBOARD_KEY_c0223=w
  KEYBOARD_KEY_c0221=e
@@ -1734,7 +1737,7 @@ evdev:input:b0003v1038p0210*
  KEYBOARD_KEY_70079=f6
 
 # Ideazon Zboard Fang
-evdev:input:b0003v1038p0310*
+evdev:input:b0003v1038p0310:*
  KEYBOARD_KEY_70059=1
  KEYBOARD_KEY_7005b=3
  KEYBOARD_KEY_70040=equal
@@ -1758,21 +1761,21 @@ evdev:input:b0003v1038p0310*
 ###########################################################
 
 # Common Volume Keys
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*SIEMENS:pnAMILO*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*SIEMENS:pnAMILO*:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFOXCONN:pnQBOOK:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMTC:pn*:pvrA0:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMio*Technology:pnN890:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPEGATRON*CORP.:pnSpring*Peak:*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*[uU][35]0[05]*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSATELLITE*[uU][35]0[05]*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*Pro*[uU]300*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnEQUIUM [uU][35]0[05]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*[uU][35]0[05]*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSATELLITE*[uU][35]0[05]*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*Pro*[uU]300*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnEQUIUM [uU][35]0[05]*:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnViooo*Corporation:pnPT17:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHANNspree:pnSN10E100:*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pni1520M:*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pn*nScreen*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pnJoybook*Lite*:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pn*nScreen*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pnJoybook*Lite*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:*
  KEYBOARD_KEY_a0=!                                      # mute
  KEYBOARD_KEY_ae=!                                      # volume down
  KEYBOARD_KEY_b0=!                                      # volume up
@@ -1786,15 +1789,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:pvr*
 # with an accompanying variant (defined with XKB_FIXED_VARIANT) if necessary.
 
 # Yubico Yubico Yubikey II"
-evdev:input:b0003v1050p0010*
+evdev:input:b0003v1050p0010:*
 # Yubico Yubikey NEO OTP+CCID
-evdev:input:b0003v1050p0111*
+evdev:input:b0003v1050p0111:*
 # Yubico Yubikey NEO OTP+U2F+CCID
-evdev:input:b0003v1050p0116*
+evdev:input:b0003v1050p0116:*
 # OKE Electron Company USB barcode reader
-evdev:input:b0003v05FEp1010*
- XKB_FIXED_LAYOUT="us"
- XKB_FIXED_VARIANT=""
+evdev:input:b0003v05FEp1010:*
+ XKB_FIXED_LAYOUT=us
+ XKB_FIXED_VARIANT=
 
 ######################### LACK OF MODIFIER LEDS ############################
 # This section lists keyboard which do not have their own LEDs for some
@@ -1805,34 +1808,34 @@ evdev:input:b0003v05FEp1010*
 # Presence of a LED is implicit when the property is absent.
 
 # Logitech K750
-evdev:input:b0003v046Dp4002*
+evdev:input:b0003v046Dp4002:*
  KEYBOARD_LED_NUMLOCK=0
  KEYBOARD_LED_CAPSLOCK=0
 
 # PFU Limited HHKB Professional JP
-evdev:input:b0003v04FEp000D*
+evdev:input:b0003v04FEp000D:*
  KEYBOARD_LED_NUMLOCK=0
  KEYBOARD_LED_CAPSLOCK=0
 
 # Lenovo ThinkPad T430s
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT430s
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT430s:*
  KEYBOARD_LED_CAPSLOCK=0
 
 # Lenovo ThinkPad T440s
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s:*
  KEYBOARD_LED_CAPSLOCK=0
 
 # Lenovo ThinkPad T450s
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT450s
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT450s:*
  KEYBOARD_LED_CAPSLOCK=0
 
 # Lenovo ThinkPad T560s
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT560s
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT560s:*
  KEYBOARD_LED_CAPSLOCK=0
  KEYBOARD_LED_NUMLOCK=0
 
 # Lenovo ThinkPad X1 Carbon 3rd Gen
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd:*
  KEYBOARD_LED_CAPSLOCK=0
 
 ######################### FIXED MODEL DEVICES #############################
@@ -1841,6 +1844,6 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd
 # The model must be an xkb compatible model (defined with XKB_FIXED_MODEL).
 
 # Chromebooks
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr*
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPeppy:pvr*
- XKB_FIXED_MODEL="chromebook"
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPeppy:*
+ XKB_FIXED_MODEL=chromebook
index 7b80e60ee5aa15b9136e56ea69dd9de0a5cc2303..7079736a8faa718c05ebd851727575a822eaafca 100644 (file)
@@ -3,17 +3,17 @@
 # The lookup keys are composed in:
 #   60-sensor.rules
 #
-# Note: The format of the "sensor:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
+# Note: The format of the "sensor:" prefix match key is a contract between the
+# rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily expected to be a stable
+# ABI.
 #
 # Match string formats:
-# sensor:modalias:<parent device modalias>:dmi:<dmi string>
+# sensor:modalias:<parent modalias pattern>:dmi:<dmi pattern>
 #
-# The device modalias can be seen in the `modalias` file
-# of the sensor parent, for example:
-# cat /sys/`udevadm info -q path -n /dev/iio:device0`/../modalias
+# The device modalias can be seen in the `modalias` file of the sensor parent,
+# for example:
+#   cat /sys/`udevadm info -q path -n /dev/iio:device0`/../modalias
 #
 # The full DMI string of the running machine can be read from
 #   /sys/class/dmi/id/modalias
@@ -46,7 +46,7 @@
 # where <matrix> is a mount-matrix in the format specified in the IIO
 # subsystem[1]. The default, when unset, is equivalent to:
 #   ACCEL_MOUNT_MATRIX=1, 0, 0; 0, 1, 0; 0, 0, 1
-# eg. the identity matrix.
+# eg. the identity matrix,
 # and <value> is an integer value above which an object is considered
 # close by a proximity sensor:
 #   PROXIMITY_NEAR_LEVEL=100
 # or 'display'. The default, when unset, is equivalent to:
 #    ACCEL_LOCATION=display
 #
+# All matches should end in ':*' to allow future expansions of the match key.
+
 # Sort by brand, model
 
 #########################################
 # Acer
 #########################################
-sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-011*
+sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-011:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-012*
+sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-012:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:BOSC0200*:dmi:*svnAcer*:*TP-SW5-017-17BU*
+sensor:modalias:acpi:BOSC0200*:dmi:*svnAcer*:*TP-SW5-017-17BU:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, -1
 
 sensor:modalias:acpi:BMA250E*:dmi:*:svnAcer:pnIconiaW1-810:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
-sensor:modalias:acpi:SMO8500:*:dmi:*Acer*:pnOneS1002*
+sensor:modalias:acpi:SMO8500:*:dmi:*Acer*:pnOneS1002:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1
 
 sensor:modalias:acpi:KIOX0009*:dmi:*:svnAcer:pnOneS1003:*
@@ -93,11 +95,9 @@ sensor:modalias:acpi:KIOX0009*:dmi:*:svnAcer:pnOneS1003:*
 sensor:modalias:acpi:BOSC0200*:dmi:*:svnAcer*:pnSwitchSW312-31:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:BOSC0200*:dmi:*svn*Acer*:*pn*Spin*SP111-32*
-sensor:modalias:acpi:BOSC0200*:dmi:*svn*Acer*:*pn*Spin*SP111-33*
- ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
-
-sensor:modalias:acpi:BOSC0200*:dmi:*svnAcer*:*pnSpinSP111-34*
+sensor:modalias:acpi:BOSC0200*:dmi:*svn*Acer*:*pn*Spin*SP111-32:*
+sensor:modalias:acpi:BOSC0200*:dmi:*svn*Acer*:*pn*Spin*SP111-33:*
+sensor:modalias:acpi:BOSC0200*:dmi:*svnAcer*:*pnSpinSP111-34:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
@@ -109,48 +109,49 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnARCHOS:pnARCHOS80Cesium:*
 #########################################
 # AsusTek
 #########################################
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100CHI*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100CHI:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT300CHI*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT300CHI:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnM80TA*
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TA*
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT200TA*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnM80TA:*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TA:*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT200TA:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnTP201SA*
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pn*E205SA*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnTP201SA:*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pn*E205SA:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LA*
-sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LD*
+sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LA:*
+sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LD:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LN*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LN:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:KXJ2109*:dmi:*:svnASUSTeK*:pnME176C*
+sensor:modalias:acpi:KXJ2109*:dmi:*:svnASUSTeK*:pnME176C:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
-sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LJ*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LJ:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP500LAB*
-sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP500LB*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP500LAB:*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP500LB:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LD*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LD:*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LAB:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
-sensor:modalias:acpi:BOSC0200*:dmi:*svn*ASUSTeK*:*pn*TP412UA*
+sensor:modalias:acpi:BOSC0200*:dmi:*svn*ASUSTeK*:*pn*TP412UA:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
 # Axxo
 #########################################
-sensor:modalias:acpi:SMO8500*:dmi:*:svnStandard:pnWCBT1011:*
+sensor:modalias:acpi:SMO8500*:dmi:*:svnStandard:pnWCBT1011::*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
@@ -169,6 +170,10 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnD2D3_Vi8A1:*
 sensor:modalias:acpi:BMA250E*:dmi:bvnINSYDECorp.:bvrG1D_S165*:svnilife:pnS165:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
+# Chuwi Hi8 (CWI509)
+sensor:modalias:acpi:BMA250E*:dmi:*svnilife*:pnS806:*
+ ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
+
 # Chuwi Hi8 Pro (CWI513)
 sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnX1D3_C806N:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
@@ -203,8 +208,8 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnChuwi*:pnHi13:*
 # Chuwi HiBook does not have its product name filled, so we
 # match the entire dmi-alias, assuming that the use of a BOSC0200 +
 # bios-version + bios-date combo is unique
-sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
+sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
 # Chuwi HiBook Pro (CWI526)
@@ -214,7 +219,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
 # Chuwi CoreBook
 # Chuwi CoreBook does not have its product name filled, so we
 # match the entire dmi-alias
-sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:
+sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
@@ -262,7 +267,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnALLDOCUBE:pni1102:*
 #########################################
 # Cytrix (Mytrix)
 #########################################
-sensor:modalias:acpi:*KIOX000A*:dmi:*svn*CytrixTechnology:*pn*Complex11t*
+sensor:modalias:acpi:*KIOX000A*:dmi:*svn*CytrixTechnology:*pn*Complex11t:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
@@ -271,18 +276,24 @@ sensor:modalias:acpi:*KIOX000A*:dmi:*svn*CytrixTechnology:*pn*Complex11t*
 sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnVostro5581:*
  ACCEL_LOCATION=base
 
+sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnLatitude9520:*:ct10:*
+ ACCEL_LOCATION=base
+
+sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnLatitude7420:*
+ ACCEL_LOCATION=base
+
 # Dell Venue 8 Pro 3845
-sensor:modalias:acpi:INVN6500*:dmi:*svnDellInc.*:pnVenue8Pro3845*
+sensor:modalias:acpi:INVN6500*:dmi:*svnDellInc.*:pnVenue8Pro3845:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 # Dell Venue 10 Pro 5055
-sensor:modalias:acpi:INVN6500*:dmi:*svnDell*:pnVenue10Pro5055*
+sensor:modalias:acpi:INVN6500*:dmi:*svnDell*:pnVenue10Pro5055:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
 # DEXP
 #########################################
-sensor:modalias:acpi:SMO8500*:dmi:*svn*DEXP*:*pn*DEXPOEM*
+sensor:modalias:acpi:SMO8500*:dmi:*svn*DEXP*:*pn*DEXPOEM:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 #########################################
@@ -296,7 +307,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnDigma:pnCITIE203ES2010EW:*
 #########################################
 # Endless
 #########################################
-sensor:modalias:acpi:ACCE0001*:dmi:*svnEndless*:*pnELT-NL3*
+sensor:modalias:acpi:ACCE0001*:dmi:*svnEndless*:*pnELT-NL3:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 0, 0, -1; -1, 0, 0
 
 #########################################
@@ -316,19 +327,19 @@ sensor:modalias:acpi:KIOX010A*:dmi:*:svnGEO*:pnGeoFlex*:*
 #########################################
 # Google Chromebooks
 #########################################
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
+sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
 # caroline board (Samsung Chromebook Pro) reports itself as svnGoogle
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
+sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
 # Dell Inspiron Chromebook 14 2-in-1
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*
+sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
 # nocturne board (Google Pixel Slate)
-sensor:modalias:platform:cros-ec-accel:dmi:*Google_Nocturne*
+sensor:modalias:platform:cros-ec-accel:dmi:*Google_Nocturne*:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
 #########################################
@@ -348,13 +359,13 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnINSYDECorp.:bvrBYT70A.YNCHENG.WIN.007:*:sv
 # and no other devices have both board_name *and* product_name set to
 # "Default string". So combined with the sensor modalias and BIOS date this
 # should be unique enough to identify the GPDwin
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
  ACCEL_LOCATION=base
 
 #########################################
@@ -382,7 +393,7 @@ sensor:modalias:i2c:bmc150_accel:dmi:*:svnHewlett-Packard:pnHPPavilionx2Detachab
 # The I.T.Works TW891 2-in-1's DMI has the product-name field set, but not
 # the sys-vendor field. This makes the DMI data a bit generic, so we match
 # the whole dmi modalias, except for the BIOS version/date
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:*:svnTobefilledbyO.E.M.:pnTW891:pvrTobefilledbyO.E.M.:rvnTobefilledbyO.E.M.:rnTW891:rvr1.0:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:*:svnTobefilledbyO.E.M.:pnTW891:pvrTobefilledbyO.E.M.:rvnTobefilledbyO.E.M.:rnTW891:rvr1.0:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 # I.T.Works TW701 7" windows tablet, same hw as Trekstor ST70416-6
@@ -398,7 +409,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnIRBIS:pnTW90:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
 
 # NB111
-sensor:modalias:acpi:KIOX010A*:dmi:*svn*IRBIS*:*pn*NB111*
+sensor:modalias:acpi:KIOX010A*:dmi:*svn*IRBIS*:*pn*NB111:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 #TW118
@@ -408,7 +419,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnIRBIS:pnTW118:*
 #########################################
 # iOTA 360
 #########################################
-sensor:modalias:acpi:KIOX000A*:dmi:*svn*iOTA*:*pn*IOTA2210*
+sensor:modalias:acpi:KIOX000A*:dmi:*svn*iOTA*:*pn*IOTA2210:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 #########################################
@@ -416,7 +427,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*svn*iOTA*:*pn*IOTA2210*
 #########################################
 
 # EZpad mini 3
-sensor:modalias:acpi:BOSC0200*:dmi:bvnINSYDECorp.:bvrjumperx.T87.KFBNEE*
+sensor:modalias:acpi:BOSC0200*:dmi:bvnINSYDECorp.:bvrjumperx.T87.KFBNEE:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 # EZpad 6 Pro
@@ -436,10 +447,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnINSYDECorp.:bvrVISION.I22K*:svnKAZAM:pnVIS
 #########################################
 # Lamina
 #########################################
-sensor:modalias:acpi:SMO8500*:dmi:*svnLamina*:*pnT701BR.SE*
+sensor:modalias:acpi:SMO8500*:dmi:*svnLamina*:*pnT701BR.SE:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
-sensor:modalias:acpi:KIOX000A*:dmi:*svnLAMINA:pnT-1016BNORD*
+sensor:modalias:acpi:KIOX000A*:dmi:*svnLAMINA:pnT-1016BNORD:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
@@ -448,7 +459,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*svnLAMINA:pnT-1016BNORD*
 sensor:modalias:acpi:NCPE0388*:dmi:*:rnLenovoYOGA510-14IKB:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1
 
-sensor:modalias:acpi:BOSC0200*:dmi:*ThinkPadYoga11e3rdGen*
+sensor:modalias:acpi:BOSC0200*:dmi:*ThinkPadYoga11e3rdGen:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
 
 # Miix3-1030
@@ -464,7 +475,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnLENOVO:pn81H3:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
 
 # IdeaPad Miix 300
-sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrMIIX300-*
+sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrMIIX300-*:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 # IdeaPad Miix 310 note this only is for BIOS version (bvr) 1HCN4?WW and 1HCN2?WW, which has
@@ -475,7 +486,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN2?WW:*:svnLENOVO:pn80SG:*
 
 # IdeaPad Miix 320, different batches use a different sensor
 sensor:modalias:acpi:*BOSC0200*:dmi:*:svnLENOVO*:pn80XF:*
-sensor:modalias:acpi:SMO8840*:dmi:*:svnLENOVO:pn80XF:pvrLenovoMIIX320*
+sensor:modalias:acpi:SMO8840*:dmi:*:svnLENOVO:pn80XF:pvrLenovoMIIX320:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 # IdeaPad Miix 510, multiple expressions match different internal names
@@ -530,6 +541,12 @@ sensor:modalias:acpi:KIOX020A*:dmi:*:pnE2221TMD60691*:*
 #########################################
 # MPMAN
 #########################################
+
+# MPMAN Converter 9, same hw as the I.T.Works TW891 2-in-1
+sensor:modalias:acpi:SMO8500*:dmi:*:svnMPMAN:pnConverter9:*
+ ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+
+# MPMAN MPWIN895C
 sensor:modalias:acpi:BMA250E*:dmi:*:svnMPMAN:pnMPWIN8900CL:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
@@ -581,7 +598,7 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnINSYDECorp.:bvrONDA.W89*:svnInsyde:pnONDATa
  ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
 
 # Onda v975w, generic DMI strings, match entire dmi modalias inc. bios-date
-sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/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
 
 #########################################
@@ -621,8 +638,8 @@ sensor:modalias:acpi:BMA250E*:dmi:*:svnShenzhenPLOYER*:pnMOMO7W:*
 # The Point of View TAB-P800W does not have its product name filled, so we
 # match the entire dmi-alias, assuming that the use of a BMA250E +
 # bios-version + bios-date combo is unique
-sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
-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.:
+sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
+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)
@@ -644,7 +661,7 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnProwise:pnPT301:*
 #########################################
 
 # SCT101CTM
-sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrSCH12i.WJ210Z.KtBJRCA03*
+sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrSCH12i.WJ210Z.KtBJRCA03:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
@@ -676,7 +693,7 @@ sensor:modalias:acpi:SMO8500*:dmi:*bd12/19/2014:*:rvnTECLAST:rntPAD:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
 # Teclast X98 Plus I (A5C6), generic DMI strings, match entire dmi modalias inc. bios-date
-sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 # Teclast X98 Plus II
@@ -688,7 +705,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX98PlusII:*
 #########################################
 
 # Thundersoft TST168 tablet, generic DMI strings, match entire dmi modalias inc. bios-date
-sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/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=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
index 9d5c4fc06916e5cd2cb284dd94120d19a2962b84..f72a69dd27021135f08ca126d51f1ee81563e327 100644 (file)
@@ -36,6 +36,8 @@
 #
 #   If the property is missing, user-space can assume:
 #   ID_INPUT_JOYSTICK_INTEGRATION=external
+#
+# All matches should end in ':*' to allow future expansions of the match key.
 
 joystick:bluetooth:*
  ID_INPUT_JOYSTICK_INTEGRATION=external
@@ -45,6 +47,6 @@ joystick:bluetooth:*
 ###########################################################
 
 # GPD Win, Classic and XBox 360 compat modes
-joystick:usb:v11c5p5507*
-joystick:usb:v045ep028e*
+joystick:usb:v11c5p5507:*
+joystick:usb:v045ep028e:*
  ID_INPUT_JOYSTICK_INTEGRATION=internal
index d0a2a22709a063ad0142f4b3d9204b078a14f256..0bdac6cdb44b744722f317e6981a7c01f6c14f8f 100644 (file)
@@ -6,35 +6,37 @@
 # The lookup keys are composed in:
 #   70-mouse.rules
 #
-# Note: The format of the "mouse:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
+# Note: The format of the "mouse:" prefix match key is a contract between the
+# rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily expected to be a stable
+# ABI.
 #
-# Match string format:
+# Match key format:
 # mouse:<subsystem>:v<vid>p<pid>:name:<name>:
 #
 # Supported subsystems: usb, bluetooth
 # vid/pid as 4-digit hex lowercase vendor/product
 #
 # if vid/pid is unavailable, use
-# mouse:*:name:<name>:
+#   mouse:*:name:<name>:*
 # if name is unavailable, use
-# mouse:<subsystem>:v<vid>p<pid>:*
+#   mouse:<subsystem>:v<vid>p<pid>:*
 #
 # For example, the following 5 matches all match the same mouse:
-# mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:
-# mouse:usb:*:name:Lenovo Optical USB Mouse:
-# mouse:usb:v17efp6019:*
-# mouse:*:name:Lenovo Optical USB Mouse:
+#   mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:*
+#   mouse:usb:*:name:Lenovo Optical USB Mouse:*
+#   mouse:usb:v17efp6019:*
+#   mouse:*:name:Lenovo Optical USB Mouse:*
+#
+# All matches should end in ':*' to allow future expansions of the match key.
 #
 # To add local entries, create a new file
 #   /etc/udev/hwdb.d/71-mouse-local.hwdb
 # and add your rules there. To load the new rules execute (as root):
 #   systemd-hwdb update
 #   udevadm trigger /dev/input/eventXX
-# where /dev/input/eventXX is the mouse in question. If in
-# doubt, simply use /dev/input/event* to reload all input rules.
+# where /dev/input/eventXX is the mouse in question. If in doubt, simply use
+# /dev/input/event* to reload all input rules.
 #
 # If your changes are generally applicable, preferably send them as a pull
 # request to
 #   udevadm info /dev/input/eventXX.
 #
 # Allowed properties are:
-#    ID_INPUT_TRACKBALL
-#    MOUSE_DPI
-#    MOUSE_WHEEL_CLICK_ANGLE
-#    MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL
-#    MOUSE_WHEEL_CLICK_COUNT
-#    MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL
+#   ID_INPUT_TRACKBALL
+#   MOUSE_DPI
+#   MOUSE_WHEEL_CLICK_ANGLE
+#   MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL
+#   MOUSE_WHEEL_CLICK_COUNT
+#   MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL
 #
 #########################################
 #         ID_INPUT_TRACKBALL            #
@@ -63,7 +65,7 @@
 #########################################
 #
 # DPI settings are specified as
-#    MOUSE_DPI=<dpi>[@<frequency>]
+#   MOUSE_DPI=<dpi>[@<frequency>]
 #
 # Where <dpi> is the resolution in dots per inch, and <frequency> the
 # sampling frequency in Hz (optional). If a device supports dynamic
 ##########################################
 # Generic
 ##########################################
-mouse:*:name:*Trackball*:
-mouse:*:name:*trackball*:
-mouse:*:name:*TrackBall*:
+mouse:*:name:*Trackball*:*
+mouse:*:name:*trackball*:*
+mouse:*:name:*TrackBall*:*
  ID_INPUT_TRACKBALL=1
 
 ##########################################
@@ -153,7 +155,7 @@ mouse:*:name:*TrackBall*:
 # Apple MagicMouse
 # Note: this device changes name once connected to a mac, the name ends up
 # as $username`s mouse
-mouse:bluetooth:v05acp030d:name:*:
+mouse:bluetooth:v05acp030d:name:*:*
  MOUSE_DPI=1300@1000
 
 ##########################################
@@ -161,7 +163,7 @@ mouse:bluetooth:v05acp030d:name:*:
 ##########################################
 
 # Chicony 2.4G Multimedia Wireless Kit MG-0919
-mouse:usb:v04f2p0963:name:Chicony 2.4G Multimedia Wireless Kit:
+mouse:usb:v04f2p0963:name:Chicony 2.4G Multimedia Wireless Kit:*
  MOUSE_DPI=1000@142
 
 ##########################################
@@ -169,15 +171,15 @@ mouse:usb:v04f2p0963:name:Chicony 2.4G Multimedia Wireless Kit:
 ##########################################
 
 # Dell MUAR DEL7
-mouse:usb:v413cp3012:name:Dell Dell USB Optical Mouse:
+mouse:usb:v413cp3012:name:Dell Dell USB Optical Mouse:*
  MOUSE_DPI=400@166
 
 # Dell USB Laser Mouse
-mouse:usb:v046dpc063:name:DELL DELL USB Laser Mouse:
+mouse:usb:v046dpc063:name:DELL DELL USB Laser Mouse:*
  MOUSE_DPI=1000@125
 
 # Dell MS116t
-mouse:usb:v413cp301a:name:PixArt Dell MS116 USB Optical Mouse:
+mouse:usb:v413cp301a:name:PixArt Dell MS116 USB Optical Mouse:*
  MOUSE_DPI=1000@125
 
 ##########################################
@@ -185,14 +187,14 @@ mouse:usb:v413cp301a:name:PixArt Dell MS116 USB Optical Mouse:
 #########################################
 
 # Dynex Wired Optical Mouse (DX-WMSE2)
-mouse:usb:v0461p4d46:name:USB Optical Mouse:
+mouse:usb:v0461p4d46:name:USB Optical Mouse:*
  MOUSE_DPI=1000@125
 
 ##########################################
 # Fujitsu Siemens
 ##########################################
 
-mouse:usb:v0461p4d16:name:USB Optical Mouse:
+mouse:usb:v0461p4d16:name:USB Optical Mouse:*
  MOUSE_DPI=500@125
 
 ##########################################
@@ -200,7 +202,7 @@ mouse:usb:v0461p4d16:name:USB Optical Mouse:
 ##########################################
 
 # SNES Mouse plugged into a Retrode 2
-mouse:usb:v0403p97c1:name:Retrode SNES Mouse:
+mouse:usb:v0403p97c1:name:Retrode SNES Mouse:*
  MOUSE_DPI=235@126
 
 ##########################################
@@ -208,11 +210,11 @@ mouse:usb:v0403p97c1:name:Retrode SNES Mouse:
 ##########################################
 
 # FM-901 Wireless Mouse
-mouse:usb:v1ea7p000b:name:2.4G RF Mouse:
+mouse:usb:v1ea7p000b:name:2.4G RF Mouse:*
  MOUSE_DPI=*800@125 1600@125
 
 # WK-727
-mouse:usb:v04d9p0499:name:*
+mouse:usb:v04d9p0499:name:*:*
  MOUSE_DPI=800@125
 
 ##########################################
@@ -220,7 +222,7 @@ mouse:usb:v04d9p0499:name:*
 ##########################################
 
 # HandShoe Mouse
-mouse:usb:v192fp0916:name:USB Optical Mouse:
+mouse:usb:v192fp0916:name:USB Optical Mouse:*
  MOUSE_DPI=1000@128
 
 ##########################################
@@ -228,7 +230,7 @@ mouse:usb:v192fp0916:name:USB Optical Mouse:
 ##########################################
 
 # Hoverstop active ergonomic mouse
-mouse:usb:v088dp1234:name:HoverStop NL Hoverstop active ergonomic mouse:
+mouse:usb:v088dp1234:name:HoverStop NL Hoverstop active ergonomic mouse:*
  MOUSE_DPI=400@129
 
 ##########################################
@@ -236,18 +238,18 @@ mouse:usb:v088dp1234:name:HoverStop NL Hoverstop active ergonomic mouse:
 ##########################################
 
 # HP USB 1000dpi Laser Mouse
-mouse:usb:v0458p0133:name:Mouse Laser Mouse:
+mouse:usb:v0458p0133:name:Mouse Laser Mouse:*
  MOUSE_DPI=1000@125
  MOUSE_WHEEL_CLICK_ANGLE=15
 
 # HP X1000
 # Dell MS111-T
-mouse:usb:v093ap2510:name:PixArt USB Optical Mouse:
-mouse:usb:v093ap2510:name:PIXART USB OPTICAL MOUSE:
+mouse:usb:v093ap2510:name:PixArt USB Optical Mouse:*
+mouse:usb:v093ap2510:name:PIXART USB OPTICAL MOUSE:*
  MOUSE_DPI=1000@125
 
 # HP X1200 Optical Mouse
-mouse:usb:v03f0p0641:name:PixArt HP X1200 USB Optical Mouse:
+mouse:usb:v03f0p0641:name:PixArt HP X1200 USB Optical Mouse:*
  MOUSE_DPI=1100@125
 
 ##########################################
@@ -263,7 +265,7 @@ mouse:usb:v04b3p3107:name:*
 ##########################################
 
 # Kensington Expert Mouse trackball
-mouse:usb:v047dp1020:*Kensington Expert Mouse*
+mouse:usb:v047dp1020:*Kensington Expert Mouse*:*
  ID_INPUT_TRACKBALL=1
 
 ##########################################
@@ -271,31 +273,31 @@ mouse:usb:v047dp1020:*Kensington Expert Mouse*
 ##########################################
 
 # Lenovo Optical USB Mouse
-mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:
+mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:*
  MOUSE_DPI=1000@125
 
 # Lenovo M-U0025-O
-mouse:usb:v17efp6019:name:Logitech Lenovo USB Optical Mouse:
+mouse:usb:v17efp6019:name:Logitech Lenovo USB Optical Mouse:*
  MOUSE_DPI=1000@166
 
 # Lenovo USB mouse model MO28UOL
-mouse:usb:v04b3p310c:name:USB Optical Mouse:
+mouse:usb:v04b3p310c:name:USB Optical Mouse:*
  MOUSE_DPI=400@142
 
 # Lenovo Precision USB Mouse
-mouse:usb:v17efp6050:name:Lenovo Precision USB Mouse:
+mouse:usb:v17efp6050:name:Lenovo Precision USB Mouse:*
  MOUSE_DPI=1200@127
 
 # Lenovo MOBGUL
-mouse:usb:v17efp601d:name:Primax Lenovo Laser Mouse:
+mouse:usb:v17efp601d:name:Primax Lenovo Laser Mouse:*
  MOUSE_DPI=1600@125
 
 # Lenovo MOBGULA
-mouse:usb:v17efp6045:name:Lenovo USB 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:usb:v17efp6044:name:ThinkPad USB Laser Mouse:*
  MOUSE_DPI=1200@125
 
 ##########################################
@@ -310,135 +312,135 @@ mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse:
 ## G Series ##
 
 # Logitech G5 Laser Mouse
-mouse:usb:v046dpc049:name:Logitech USB Gaming Mouse:
+mouse:usb:v046dpc049:name:Logitech USB Gaming Mouse:*
  MOUSE_DPI=400@500 *800@500 2000@500
 
 # Logitech G500s Laser Gaming Mouse
-mouse:usb:v046dpc24e:name:Logitech G500s Laser Gaming Mouse:
+mouse:usb:v046dpc24e:name:Logitech G500s Laser Gaming Mouse:*
  MOUSE_DPI=400@500 *800@500 2000@500
 
 # Logitech G9
-mouse:usb:v046dpc048:name:Logitech G9 Laser Mouse:
+mouse:usb:v046dpc048:name:Logitech G9 Laser Mouse:*
  MOUSE_DPI=400@1000 800@1000 *1600@1000
 
 # Logitech G9x [Call of Duty MW3 Edition]
-mouse:usb:v046dpc249:name:Logitech G9x Laser Mouse:
+mouse:usb:v046dpc249:name:Logitech G9x Laser Mouse:*
  MOUSE_DPI=400@1000 800@1000 *1600@1000 3200@1000
 
 # Logitech G100s Optical Gaming Mouse
-mouse:usb:v046dpc247:name:Logitech G100s Optical Gaming Mouse:
+mouse:usb:v046dpc247:name:Logitech G100s Optical Gaming Mouse:*
  MOUSE_DPI=*1000@500 1750@500 2500@500
 
 # Logitech G400 (Wired)
-mouse:usb:v046dpc245:name:Logitech Gaming Mouse G400:
+mouse:usb:v046dpc245:name:Logitech Gaming Mouse G400:*
  MOUSE_DPI=400@1000 *800@1000 1800@1000 3600@1000
 
 # Logitech G400s (Wired)
-mouse:usb:v046dpc24c:name:Logitech G400s Optical Gaming Mouse:
+mouse:usb:v046dpc24c:name:Logitech G400s Optical Gaming Mouse:*
  MOUSE_DPI=400@1000 *800@1000 2000@1000 4000@1000
 
 # Logitech G402 Hyperion Fury
-mouse:usb:v046dpc07e:name:Logitech Gaming Mouse G402:
+mouse:usb:v046dpc07e:name:Logitech Gaming Mouse G402:*
  MOUSE_DPI=400@1000 *800@1000 1600@1000 3200@1000
 
 # Logitech G500 Mouse
-mouse:usb:v046dpc068:name:Logitech G500:
+mouse:usb:v046dpc068:name:Logitech G500:*
  MOUSE_DPI=*1600@500 2600@500 3600@500
 
 # Logitech G502 Proteus Spectrum
-mouse:usb:v046dpc332:name:Logitech Gaming Mouse G502:
+mouse:usb:v046dpc332:name:Logitech Gaming Mouse G502:*
 # Logitech G502 HERO SE
-mouse:usb:v046dpc08b:name:Logitech G502 HERO SE:
+mouse:usb:v046dpc08b:name:Logitech G502 HERO SE:*
 # Logitech G502 Hero
-mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse:
+mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse:*
  MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000
 
 # Logitech G700 Laser Mouse (Wired)
-mouse:usb:v046dpc06b:name:Logitech G700 Laser Mouse:
+mouse:usb:v046dpc06b:name:Logitech G700 Laser Mouse:*
 # Logitech G700 Laser Mouse (Wireless)
-mouse:usb:v046dpc531:name:Logitech USB Receiver:
+mouse:usb:v046dpc531:name:Logitech USB Receiver:*
  MOUSE_DPI=*1000@500 3800@500 500@1000 1500@1000 2000@1000
 
 # Logitech G703 (Wired)
-mouse:usb:v046dpc087:name:Logitech G703 Wired/Wireless Gaming Mouse:
+mouse:usb:v046dpc087:name:Logitech G703 Wired/Wireless Gaming Mouse:*
 # Logitech G703 (Wireless)
-mouse:usb:v046dpc539:name:Logitech USB Receiver Mouse:
+mouse:usb:v046dpc539:name:Logitech USB Receiver Mouse:*
  MOUSE_DPI=400@1000 800@1000 *1600@1000 3200@1000
 
 ## M Series ##
 
 # Logitech Wireless Mouse M185
-mouse:usb:v046dp4008:name:Logitech M185:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008:
+mouse:usb:v046dp4008:name:Logitech M185:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008:*
  MOUSE_DPI=1000@125
 
 # Logitech Wireless Mouse M510
-mouse:usb:v046dp1025:name:Logitech M510:
+mouse:usb:v046dp1025:name:Logitech M510:*
  MOUSE_DPI=1000@125
 
 # Logitech M705 (marathon mouse)
-mouse:usb:v046dp101b:name:Logitech M705:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b:
+mouse:usb:v046dp101b:name:Logitech M705:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b:*
  MOUSE_DPI=1000@125
 
 # Logitech M705 (newer version?)
-mouse:usb:v046dp406d:name:Logitech M705:
+mouse:usb:v046dp406d:name:Logitech M705:*
  MOUSE_DPI=1000@167
 
 # Logitech M305 Wireless Optical Mouse
-mouse:usb:v046dpc52f:name:Logitech USB Receiver:
+mouse:usb:v046dpc52f:name:Logitech USB Receiver:*
  MOUSE_DPI=1000@170
 
 # Logitech Wireless Mouse M310
-mouse:usb:v046dp1024:name:Logitech M310:
+mouse:usb:v046dp1024:name:Logitech M310:*
  MOUSE_DPI=1100@168
 
 # Logitech Wireless Mouse M325
-mouse:usb:v046dp400a:name:Logitech M325:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:400a:
+mouse:usb:v046dp400a:name:Logitech M325:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:400a:*
  MOUSE_DPI=600@166
  MOUSE_WHEEL_CLICK_ANGLE=20
 
 # Logitech M570 trackball
-mouse:usb:v046dp1028:name:Logitech M570:
+mouse:usb:v046dp1028:name:Logitech M570:*
  MOUSE_DPI=540@167
  ID_INPUT_TRACKBALL=1
 
 ## MX Series ##
 
 # Logitech Performance MX
-mouse:usb:v046dp101a:name:Logitech Performance MX:
+mouse:usb:v046dp101a:name:Logitech Performance MX:*
  MOUSE_DPI=1000@166
 
 # Logitech MX Revolution
-mouse:usb:v046dpc51a:name:Logitech USB Receiver:
+mouse:usb:v046dpc51a:name:Logitech USB Receiver:*
  MOUSE_DPI=800@200
 
 # Logitech MX 518
-mouse:usb:v046dpc01e:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc01e:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=400@125 *800@125 1600@125
 
 # Logitech MX1000 Laser Cordless Mouse
-mouse:bluetooth:v046dpb003:name:Logitech MX1000 mouse:
+mouse:bluetooth:v046dpb003:name:Logitech MX1000 mouse:*
  MOUSE_DPI=800@80
 
 # Logitech Anywhere MX
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:1017:
-mouse:usb:v046dp1017:name:Logitech Anywhere MX:
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:1017:*
+mouse:usb:v046dp1017:name:Logitech Anywhere MX:*
  MOUSE_WHEEL_CLICK_ANGLE=20
 
 # Logitech Anywhere MX 2S (via Logitech Unifying Receiver)
-mouse:usb:v046dp406a:name:Logitech MX Anywhere 2S:
+mouse:usb:v046dp406a:name:Logitech MX Anywhere 2S:*
  MOUSE_WHEEL_CLICK_ANGLE=20
 
 # Logitech Anywhere MX 2S (via Bluetooth)
-mouse:bluetooth:v046dpb01a:name:MX Anywhere 2S Mouse:
+mouse:bluetooth:v046dpb01a:name:MX Anywhere 2S Mouse:*
  MOUSE_WHEEL_CLICK_ANGLE=20
 
 # Logitech MX Master (via Logitech Unifying Receiver)
 # Horiz wheel has 14 stops, angle is rounded up
-mouse:usb:v046dp4060:name:Logitech MX Master:
-mouse:usb:v046dp4041:name:Logitech MX Master:
+mouse:usb:v046dp4060:name:Logitech MX Master:*
+mouse:usb:v046dp4041:name:Logitech MX Master:*
  MOUSE_DPI=1000@166
  MOUSE_WHEEL_CLICK_ANGLE=15
  MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
@@ -447,7 +449,7 @@ mouse:usb:v046dp4041:name:Logitech MX Master:
 
 # Logitech MX Master (via Bluetooth)
 # Horiz wheel has 14 stops, angle is rounded up
-mouse:bluetooth:v046dpb012:name:MX Master Mouse:
+mouse:bluetooth:v046dpb012:name:MX Master Mouse:*
  MOUSE_DPI=1000@2000
  MOUSE_WHEEL_CLICK_ANGLE=15
  MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
@@ -456,7 +458,7 @@ mouse:bluetooth:v046dpb012:name:MX Master Mouse:
 
 # Logitech MX Master 2S (via Logitech Unifying Receiver)
 # Horiz wheel has 14 stops, angle is rounded up
-mouse:usb:v046dp4069:name:Logitech MX Master 2s:
+mouse:usb:v046dp4069:name:Logitech MX Master 2s:*
  MOUSE_DPI=1000@125
  MOUSE_WHEEL_CLICK_ANGLE=15
  MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
@@ -465,7 +467,7 @@ mouse:usb:v046dp4069:name:Logitech MX Master 2s:
 
 # Logitech MX Master 2S (via Bluetooth)
 # Horiz wheel has 14 stops, angle is rounded up
-mouse:bluetooth:v046dpb019:name:MX Master 2S Mouse:
+mouse:bluetooth:v046dpb019:name:MX Master 2S Mouse:*
  MOUSE_DPI=1000@2000
  MOUSE_WHEEL_CLICK_ANGLE=15
  MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
@@ -473,176 +475,176 @@ mouse:bluetooth:v046dpb019:name:MX Master 2S Mouse:
  MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL=14
 
 # Logitech MX Ergo (via Bluetooth)
-mouse:bluetooth:v046dpb01d:name:MX Ergo Mouse:
+mouse:bluetooth:v046dpb01d:name:MX Ergo Mouse:*
  ID_INPUT_TRACKBALL=1
 
 ## Other ##
 
 # Logitech M-BJ58 Optical Mouse
-mouse:usb:v046dpc00e:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc00e:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=400@125
 
 # Logitech Mini Optical Mouse
-mouse:usb:v046dpc016:name:Logitech Optical USB Mouse:
+mouse:usb:v046dpc016:name:Logitech Optical USB Mouse:*
  MOUSE_DPI=400@125
 
 # Logitech MX310 Optical Mouse
-mouse:usb:v046dpc01b:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc01b:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=400@125
 
 # Logitech USB-PS/2 M-BT58
-mouse:usb:v046dpc03e:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc03e:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=400@125
 
 # Logitech TrackMan Marble Wheel USB
-mouse:usb:v046dpc401:name:Logitech USB-PS/2 Trackball:
+mouse:usb:v046dpc401:name:Logitech USB-PS/2 Trackball:*
  MOUSE_DPI=400@125
 
 # Logitech Cordless MouseMan Optical M-RM63
-mouse:usb:v046dpc501:name:Logitech USB Receiver:
+mouse:usb:v046dpc501:name:Logitech USB Receiver:*
  MOUSE_DPI=800@63
 
 # Logitech USB-PS/2 M-BZ96C
-mouse:usb:v046dpc045:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc045:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=600@125
 
 # Logitech MX400 Performance Laser Mouse
-mouse:usb:v046dpc043:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc043:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=800@125
 
 # Logitech MX1000 Laser Cordless Mouse
-mouse:usb:v046dpc50e:name:Logitech USB RECEIVER:
+mouse:usb:v046dpc50e:name:Logitech USB RECEIVER:*
  MOUSE_DPI=800@125
 
 # Logitech Cordless Click! Plus
-mouse:usb:v046dpc50e:name:Logitech USB Receiver:
+mouse:usb:v046dpc50e:name:Logitech USB Receiver:*
  MOUSE_DPI=800@125
 
 # Logitech, Inc. RX 300 Optical Mouse
-mouse:usb:v046dpc040:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc040:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=800@125
 
 # Logitech, Inc. RX 250 Optical Mouse
-mouse:usb:v046dpc050:name:Logitech USB-PS/2 Optical Mouse:
+mouse:usb:v046dpc050:name:Logitech USB-PS/2 Optical Mouse:*
  MOUSE_DPI=1000@142
 
 # Logitech B605 Wireless Mouse (also M505)
-mouse:usb:v046dp101d:name:Logitech B605:
-mouse:usb:v046dp101d:name:Logitech M505:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101d:
+mouse:usb:v046dp101d:name:Logitech B605:*
+mouse:usb:v046dp101d:name:Logitech M505:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101d:*
  MOUSE_DPI=900@166
 
 # Logitech Cordless Desktop Wave Mouse
-mouse:usb:v046dpc517:name:Logitech USB Receiver:
+mouse:usb:v046dpc517:name:Logitech USB Receiver:*
  MOUSE_DPI=950@125
 
 # Logitech RX1000 Laser Mouse
-mouse:usb:v046dpc046:name:Logitech USB Optical Mouse:
+mouse:usb:v046dpc046:name:Logitech USB Optical Mouse:*
  MOUSE_DPI=1000@125
 
 # Logitech M100 Optical Mouse
-mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
+mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:*
  MOUSE_DPI=1000@125
 
 # Logitech USB Laser Mouse M-U0011-O rebranded as "terra Laser"
-mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
+mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:*
  MOUSE_DPI=1000@125
 
 # Logitech USB Laser Mouse M-U0007 [M500]
-mouse:usb:v046dpc069:name:Logitech USB Laser Mouse:
+mouse:usb:v046dpc069:name:Logitech USB Laser Mouse:*
  MOUSE_DPI=1000@125
 
 # Logitech V500 Cordless Notebook Mouse
-mouse:usb:v046dpc510:name:Logitech USB Receiver:
+mouse:usb:v046dpc510:name:Logitech USB Receiver:*
  MOUSE_DPI=1000@125
 
 # Logitech M560 Wireless Mouse
-mouse:usb:v046dp402d:name:Logitech M560:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d:
+mouse:usb:v046dp402d:name:Logitech M560:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d:*
  MOUSE_DPI=1000@125
 
 # Logitech MK260 Wireless Combo Receiver aka M-R0011
-mouse:usb:v046dpc52e:name:Logitech USB Receiver:
+mouse:usb:v046dpc52e:name:Logitech USB Receiver:*
  MOUSE_DPI=1000@200
 
 # Logitech USB Laser Mouse M-UAS144 [LS1 Laser Mouse]
-mouse:usb:v046dpc062:name:Logitech USB Laser Mouse:
+mouse:usb:v046dpc062:name:Logitech USB Laser Mouse:*
  MOUSE_DPI=1200@125
 
 # Logitech T620 (or, the soap)
-mouse:usb:v046dp4027:name:Logitech T620:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4027:
+mouse:usb:v046dp4027:name:Logitech T620:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4027:*
  MOUSE_DPI=1200@250
 
 # Logitech ZoneTouch Mouse T400
-mouse:usb:v046dp4026:name:Logitech T400:
-mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4026:
+mouse:usb:v046dp4026:name:Logitech T400:*
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4026:*
  MOUSE_DPI=1300@166
 
 # Logitech TrackMan Wheel (USB)
-mouse:usb:v046dpc404:name:Logitech Trackball:
+mouse:usb:v046dpc404:name:Logitech Trackball:*
  MOUSE_DPI=300@125
 
 # Logitech Ultrathin Touch Mouse
-mouse:bluetooth:v046dpb00d:name:Ultrathin Touch Mouse:
+mouse:bluetooth:v046dpb00d:name:Ultrathin Touch Mouse:*
  MOUSE_DPI=1000@1000
 
 # ImPS/2 Logitech Wheel Mouse
-mouse:ps2:*:name:ImPS/2 Logitech Wheel Mouse:
+mouse:ps2:*:name:ImPS/2 Logitech Wheel Mouse:*
  MOUSE_DPI=400@100
 
 # ImExPS/2 Logitech Wheel Mouse
-mouse:ps2:*:name:ImExPS/2 Logitech Wheel Mouse:
+mouse:ps2:*:name:ImExPS/2 Logitech Wheel Mouse:*
  MOUSE_DPI=400@250
 
 ##########################################
 # Microsoft
 ##########################################
 
-mouse:usb:v045ep0040:name:Microsoft Microsoft 3-Button Mouse with IntelliEye(TM):
+mouse:usb:v045ep0040:name:Microsoft Microsoft 3-Button Mouse with IntelliEye(TM):*
  MOUSE_DPI=400@125
 
 # Note: unsure that these work, it's likely that all devices on these
 # receivers show up with the same vid/pid/name
 
 # Microsoft Wireless Mouse 5000
-mouse:usb:v045ep0745:name:Microsoft Microsoft® 2.4GHz Transceiver v6.0:
+mouse:usb:v045ep0745:name:Microsoft Microsoft® 2.4GHz Transceiver v6.0:*
  MOUSE_DPI=800@142
 
 # Microsoft Comfort Mouse 4500
-mouse:usb:v045ep076c:name:Microsoft Microsoft® Comfort Mouse 4500:
+mouse:usb:v045ep076c:name:Microsoft Microsoft® Comfort Mouse 4500:*
  MOUSE_DPI=1000@125
 
 # Microsoft Wireless Mobile Mouse 4000
-mouse:usb:v045ep0745:name:Microsoft Microsoft® Nano Transceiver v2.0:
+mouse:usb:v045ep0745:name:Microsoft Microsoft® Nano Transceiver v2.0:*
  MOUSE_DPI=1000@142
 
 # Microsoft Sculpt Ergonomic Mouse
-mouse:usb:v045ep07a5:name:Microsoft Microsoft® 2.4GHz Transceiver v9.0:
+mouse:usb:v045ep07a5:name:Microsoft Microsoft® 2.4GHz Transceiver v9.0:*
  MOUSE_DPI=1000@142
 
 # Microsoft Arc Touch Mouse USB
-mouse:usb:v045ep07b1:name:Microsoft Microsoft® Nano Transceiver v1.0:
+mouse:usb:v045ep07b1:name:Microsoft Microsoft® Nano Transceiver v1.0:*
  MOUSE_DPI=1400@142
 
 # Microsoft  Wireless Laser Mouse 8000
-mouse:bluetooth:v045ep0702:name:Microsoft  Wireless Laser Mouse 8000:
+mouse:bluetooth:v045ep0702:name:Microsoft  Wireless Laser Mouse 8000:*
  MOUSE_DPI=1000@1000
 
 # Microsoft Sculpt Comfort Mouse
-mouse:bluetooth:v045ep07a2:name:Microsoft Sculpt Comfort Mouse:
+mouse:bluetooth:v045ep07a2:name:Microsoft Sculpt Comfort Mouse:*
  MOUSE_DPI=1000@2000
 
 # Microsoft Arc Touch Mouse SE:
-mouse:bluetooth:v045ep07f3:name:Arc Touch Mouse SE:
+mouse:bluetooth:v045ep07f3:name:Arc Touch Mouse SE:*
  MOUSE_DPI=1000@2000
 
 # Microsoft Surface Mouse
-mouse:bluetooth:v0000p0000:name:Surface Mouse:
+mouse:bluetooth:v0000p0000:name:Surface Mouse:*
  MOUSE_DPI=2000@2000
 
 # Microsoft Classic IntelliMouse
-mouse:usb:v045ep0823:name:Microsoft Microsoft?? Classic IntelliMouse??:
+mouse:usb:v045ep0823:name:Microsoft Microsoft?? Classic IntelliMouse??:*
  MOUSE_DPI=3200@1000
 
 ##########################################
@@ -650,7 +652,7 @@ mouse:usb:v045ep0823:name:Microsoft Microsoft?? Classic IntelliMouse??:
 ##########################################
 
 #Mionix Avior 7000
-mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:
+mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:*
  MOUSE_DPI=400@1000 *1600@1000 7000@1000
  MOUSE_WHEEL_CLICK_ANGLE=15
 
@@ -659,7 +661,7 @@ mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:
 ##########################################
 
 # MODECOM MC-WM4 Wireless Optical Mouse
-mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:
+mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:*
  MOUSE_DPI=*800@126 1600@126
 
 ##########################################
@@ -667,7 +669,7 @@ mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:
 ##########################################
 
 # Oklick 406S Bluetooth Laser Mouse
-mouse:bluetooth:v056ep0061:name:Laser  BTmouse:
+mouse:bluetooth:v056ep0061:name:Laser  BTmouse:*
  MOUSE_DPI=*800@333 1600@333
 
 ##########################################
@@ -675,7 +677,7 @@ mouse:bluetooth:v056ep0061:name:Laser  BTmouse:
 ##########################################
 
 # P-Active Wireless Mouse PA-27K2
-mouse:usb:v0425p0101:name:G-Tech CHINA    USB Wireless Mouse & KeyBoard V1.01  :
+mouse:usb:v0425p0101:name:G-Tech CHINA    USB Wireless Mouse & KeyBoard V1.01  :*
  MOUSE_DPI=800@125
 
 ##########################################
@@ -683,11 +685,11 @@ mouse:usb:v0425p0101:name:G-Tech CHINA    USB Wireless Mouse & KeyBoard V1.01  :
 ##########################################
 
 # Razer Abyssus
-mouse:usb:v1532p0042:name:Razer Razer Abyssus:
+mouse:usb:v1532p0042:name:Razer Razer Abyssus:*
  MOUSE_DPI=1600@1000
 
 # Razer DeathAdder Black Edition
-mouse:usb:v1532p0029:name:Razer Razer DeathAdder:
+mouse:usb:v1532p0029:name:Razer Razer DeathAdder:*
  MOUSE_DPI=3500@1000
 
 ##########################################
@@ -695,7 +697,7 @@ mouse:usb:v1532p0029:name:Razer Razer DeathAdder:
 ##########################################
 
 # Roccat Lua (ROC-11-310)
-mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:
+mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:*
  MOUSE_DPI=250@125 500@125 1000@125 1250@125 1500@125 1750@125 2000@125 250@250 500@250 1000@250 1250@250 1500@250 1750@250 2000@250 250@500 500@500 1000@500 1250@500 1500@500 1750@500 2000@500 250@1000 500@1000 *1000@1000 1250@1000 1500@1000 1750@1000 2000@1000
  MOUSE_WHEEL_CLICK_ANGLE=15
 
@@ -704,7 +706,7 @@ mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:
 ##########################################
 
 # Sharkoon Shark Force Gaming Mouse
-mouse:usb:v093ap2521:name:USB OPTICAL MOUSE:
+mouse:usb:v093ap2521:name:USB OPTICAL MOUSE:*
  MOUSE_DPI=*1000@125 1600@125 600@125
 
 ##########################################
@@ -712,7 +714,7 @@ mouse:usb:v093ap2521:name:USB OPTICAL MOUSE:
 ##########################################
 
 # SteelSeries Sensei Raw
-mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:
+mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:*
  MOUSE_DPI=1000@1022
 
 ##########################################
@@ -720,7 +722,7 @@ mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:
 ##########################################
 
 # Trust illuminated mouse gxt 152
-mouse:usb:v145fp01ac:name:HID-compliant Mouse Trust Gaming Mouse:
+mouse:usb:v145fp01ac:name:HID-compliant Mouse Trust Gaming Mouse:*
  MOUSE_DPI=*800@528 1200@537 1600@536 2400@521
 
 ##########################################
@@ -742,7 +744,7 @@ mouse:usb:v3057p0001:*
  MOUSE_WHEEL_CLICK_ANGLE=23
 
 # Zowie ZA12
-mouse:usb:v1af3p0001:name:Kingsis Peripherals ZOWIE Gaming mouse:
+mouse:usb:v1af3p0001:name:Kingsis Peripherals ZOWIE Gaming mouse:*
  MOUSE_DPI=400@125 *800@125 1600@125 3200@125 400@500 800@500 1600@500 3200@500 400@1000 800@1000 1600@1000 3200@1000
  MOUSE_WHEEL_CLICK_COUNT=16
  MOUSE_WHEEL_CLICK_ANGLE=23
index c5c7dd9725747a8da92a7a937f07f21dfb6638a3..bcc993644e56f7fdad30f525785dc1a5bd5d5e6d 100644 (file)
@@ -13,7 +13,7 @@
 #
 # Supported hardware matches are:
 #  - Generic input devices match:
-#      evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV
+#      evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV:*
 #    This matches on the kernel modalias of the input-device, mainly:
 #    ZZZZ is the bus-id (see /usr/include/linux/input.h BUS_*), YYYY, XXXX and
 #    WWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
 #    in /sys/class/input/eventX/device/id.
 #
 #  - Input driver device name and DMI data match:
-#      evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
+#      evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*:*
 #    <input device name> is the name device specified by the driver,
 #    <vendor> is the firmware-provided string from the kernel DMI modalias,
 #    see /sys/class/dmi/id/modalias
 #
+# All matches should end in ':*' to allow future expansions of the match key.
+#
 # To add local entries, create a new file
 #   /etc/udev/hwdb.d/71-pointingstick-local.hwdb
 # and add your rules there. To load the new rules execute (as root):
@@ -76,7 +78,6 @@
 # drivers/input/mouse/trackpoint.c in the Linux kernel sources.
 #
 
-#
 # Sort by brand, model
 
 #########################################
 #########################################
 
 # Latitude D620
-evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeD620*:pvr*
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeD620*:*
  POINTINGSTICK_CONST_ACCEL=0.5
 
 # Latitude E5570
-evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE5570*:pvr*
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE5570*:*
  POINTINGSTICK_CONST_ACCEL=0.1
 
 # Latitude E6320
-evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320*:pvr*
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320*:*
  POINTINGSTICK_CONST_ACCEL=2.0
 
 # Latitude E6400
-evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr*
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:*
  POINTINGSTICK_CONST_ACCEL=1.5
 
 # Latitude E7470
-evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470*:pvr*
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470*:*
  POINTINGSTICK_CONST_ACCEL=0.6
 
 #########################################
@@ -156,6 +157,6 @@ evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX20?
  POINTINGSTICK_CONST_ACCEL=1.25
 
 # Lenovo UltraNav SK-8845 (USB keyboard)
-evdev:input:b0003v06CBp0009*
+evdev:input:b0003v06CBp0009:*
  POINTINGSTICK_CONST_ACCEL=2.5
  POINTINGSTICK_SENSITIVITY=200
index 8194d983587df17f1c8684d5af5fdb4c7acce38b..797ed3925f18f7df09eef9ad5a543d2e32c9f3b4 100644 (file)
@@ -15,6 +15,8 @@
 #
 # vid/pid as 4-digit hex lowercase vendor/product
 #
+# All matches should end in ':*' to allow future expansions of the match key.
+#
 # To add local entries, create a new file
 #   /etc/udev/hwdb.d/71-touchpad-local.hwdb
 # and add your rules there. To load the new rules execute (as root):
@@ -59,11 +61,11 @@ touchpad:usb:v044ep1221:*
 ###########################################################
 # Logitech
 ###########################################################
-touchpad:usb:v046d*
+touchpad:usb:v046dp????:*
  ID_INPUT_TOUCHPAD_INTEGRATION=external
 
 ###########################################################
 # Wacom
 ###########################################################
-touchpad:usb:v056a*
+touchpad:usb:v056ap????:*
  ID_INPUT_TOUCHPAD_INTEGRATION=external
index 3e4c3f096746ad340c02b1a7ea3e682322069d41..e7c830541d85140934bfbe9cca2e7b96bc9f3ec9 100644 (file)
@@ -63,7 +63,7 @@
  <tr class="odd"><td>Teracue AG</td><td>TCAG</td><td>12/07/2012</td> </tr>
  <tr class="even"><td>Texas Instruments</td><td>TXNW</td><td>01/01/2010</td> </tr>
  <tr class="odd"><td>The Linux Foundation</td><td>LNUX</td><td>04/04/2014</td> </tr>
- <tr class="even"><td>Toshiba Corporation</td><td>TOSB</td><td>07/07/2015</td> </tr>
+ <tr class="even"><td>Dynabook Inc.</td><td>TOSB</td><td>07/07/2015</td> </tr>
  <tr class="odd"><td>VAIO Corporation</td><td>VAIO</td><td>04/18/2014</td> </tr>
  <tr class="even"><td>Validity Sensors, Inc</td><td>VFSI</td><td>06/17/2013</td> </tr>
  <tr class="odd"><td>Wacom</td><td>WCOM</td><td>11/17/2011</td> </tr>
@@ -98,6 +98,8 @@
  <tr class="even"><td>Fujitsu Limited</td><td>FUJI</td><td>06/18/2019</td> </tr>
  <tr class="odd"><td>Phytium Technology Co. Ltd.</td><td>PHYT</td><td>02/14/2020</td> </tr>
  <tr class="even"><td>CHENGDU HAIGUANG IC DESIGN CO., LTD</td><td>HYGO</td><td>07/15/2020</td> </tr>
+ <tr class="odd"><td>PixArt imaging inc.</td><td>PIXA</td><td>07/15/2020</td> </tr>
+ <tr class="even"><td>Loongson Technology Corporation Limited</td><td>LOON</td><td>09/10/2020</td> </tr>
       </tbody>
     </table>
   </body>
index 43558082b3a17b6224b0831b3e0cf57168eb79ca..dcc442f8e91545b5c011061b8d33a873be1b39e7 100644 (file)
@@ -1247,9 +1247,6 @@ A86D5F     (base 16)              Raisecom Technology CO., LTD
                                Bayan Lepas  Penang  11900\r
                                MY\r
 \r
-A4-68-BC   (hex)               Private\r
-A468BC     (base 16)           Private\r
-\r
 00-50-79   (hex)               Private\r
 005079     (base 16)           Private\r
 \r
@@ -1586,12 +1583,6 @@ E09F2A     (base 16)             Iton Technology Corp.
                                Hong Kong  Hong Kong  999077\r
                                HK\r
 \r
-74-95-EC   (hex)               ALPS ELECTRIC CO., LTD.\r
-7495EC     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 AC-5A-EE   (hex)               China Mobile Group Device Co.,Ltd.\r
 AC5AEE     (base 16)           China Mobile Group Device Co.,Ltd.\r
                                32 Xuanwumen West Street,Xicheng District\r
@@ -1610,30 +1601,6 @@ AC5AEE     (base 16)             China Mobile Group Device Co.,Ltd.
                                Shanghai    200040\r
                                CN\r
 \r
-00-06-F7   (hex)               ALPS ELECTRIC CO., LTD.\r
-0006F7     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
-00-07-04   (hex)               ALPS ELECTRIC CO., LTD.\r
-000704     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
-00-06-F5   (hex)               ALPS ELECTRIC CO., LTD.\r
-0006F5     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
-34-C7-31   (hex)               ALPS ELECTRIC CO., LTD.\r
-34C731     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
 9C-69-B4   (hex)               IEEE Registration Authority\r
 9C69B4     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
@@ -1646,24 +1613,6 @@ AC5AEE     (base 16)             China Mobile Group Device Co.,Ltd.
                                Concord  Ontario  L4K 5C7\r
                                CA\r
 \r
-64-D4-BD   (hex)               ALPS ELECTRIC CO., LTD.\r
-64D4BD     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
-                               JP\r
-\r
-04-98-F3   (hex)               ALPS ELECTRIC CO., LTD.\r
-0498F3     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1 NISHIDA\r
-                               KAKUDA  MIYAGI PREF  9876-8501\r
-                               JP\r
-\r
-00-21-4F   (hex)               ALPS ELECTRIC CO., LTD.\r
-00214F     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
 44-B4-33   (hex)               tide.co.,ltd\r
 44B433     (base 16)           tide.co.,ltd\r
                                9F Kapeul GreatValley A-dong, Digitalro 9-ghil 32, Geumcheon-gu\r
@@ -4214,12 +4163,6 @@ E82A44     (base 16)             Liteon Technology Corporation
                                shenzhen  guangdong  518000\r
                                CN\r
 \r
-94-7B-BE   (hex)               Ubicquia\r
-947BBE     (base 16)           Ubicquia\r
-                               3281 Fairlane Farms Rd\r
-                               Wellington   FL  33449\r
-                               US\r
-\r
 EC-C0-6A   (hex)               PowerChord Group Limited\r
 ECC06A     (base 16)           PowerChord Group Limited\r
                                1 Blythe Road\r
@@ -4622,12 +4565,6 @@ C850E9     (base 16)             Raisecom Technology CO., LTD
                                Tenei-village.Iwase-country  Fukushima-prefecture  962-0512\r
                                JP\r
 \r
-88-DA-1A   (hex)               Redpine Signals, Inc.\r
-88DA1A     (base 16)           Redpine Signals, Inc.\r
-                               2107, N. First St\r
-                               San Jose  CA  95131-2019\r
-                               US\r
-\r
 98-EF-9B   (hex)               OHSUNG\r
 98EF9B     (base 16)           OHSUNG\r
                                335-4,SANHODAERO,GUMI,GYEONG BUK,KOREA\r
@@ -18890,12 +18827,6 @@ D4C766     (base 16)           Acentic GmbH
                                Seocho-gu,  Seoul  137-130\r
                                KR\r
 \r
-00-26-4E   (hex)               Rail & Road Protec GmbH\r
-00264E     (base 16)           Rail & Road Protec GmbH\r
-                               Norderhofenden 12-13\r
-                               Flensburg    24937\r
-                               DE\r
-\r
 00-26-4F   (hex)               Krüger &Gothe GmbH\r
 00264F     (base 16)           Krüger &Gothe GmbH\r
                                Atzendorfer Straße 19\r
@@ -29948,12 +29879,6 @@ D4C766     (base 16)           Acentic GmbH
                                CHIMNEY ROCK  CO  81127\r
                                US\r
 \r
-00-60-65   (hex)               BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH\r
-006065     (base 16)           BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH\r
-                               EGGELSBERG 120\r
-                               5142 EGGELSBERG    \r
-                               AT\r
-\r
 00-60-5D   (hex)               SCANIVALVE CORP.\r
 00605D     (base 16)           SCANIVALVE CORP.\r
                                1722 N. MADSON STREET\r
@@ -32825,12 +32750,6 @@ F4DBE3     (base 16)           Apple, Inc.
                                Cupertino  CA  95014\r
                                US\r
 \r
-BC-42-8C   (hex)               ALPS ELECTRIC CO., LTD.\r
-BC428C     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               nishida  6-1 \r
-                               Kakuda-City  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 F0-7C-C7   (hex)               Juniper Networks\r
 F07CC7     (base 16)           Juniper Networks\r
                                1133 Innovation Way\r
@@ -33095,12 +33014,6 @@ B0B5C3     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
                                Farmington Hills  MI  48335\r
                                US\r
 \r
-BC-0F-9A   (hex)               D-Link International\r
-BC0F9A     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 30-B2-37   (hex)               GD Midea Air-Conditioning Equipment Co.,Ltd.\r
 30B237     (base 16)           GD Midea Air-Conditioning Equipment Co.,Ltd.\r
                                Midea Global Innovation Center,Beijiao Town,Shunde\r
@@ -34211,6 +34124,531 @@ F81093     (base 16)          Apple, Inc.
                                Dongguan  Guangdong  523808\r
                                CN\r
 \r
+04-05-DD   (hex)               Shenzhen Cultraview Digital Technology Co., Ltd\r
+0405DD     (base 16)           Shenzhen Cultraview Digital Technology Co., Ltd\r
+                               F6,M6,Maqueling, High-tech park, Nanshan district\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+38-97-A4   (hex)               ELECOM CO.,LTD.\r
+3897A4     (base 16)           ELECOM CO.,LTD.\r
+                               2F Kudan First Place Bldg. 4-1-28\r
+                               Chiyoda-ku  Kudan Kita  102-0073\r
+                               JP\r
+\r
+E4-33-AE   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+E433AE     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+DC-E9-94   (hex)               CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.\r
+DCE994     (base 16)           CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.\r
+                               B22 Building,NO.51 Tongle Road, Shajing Town, Jiangnan District, Nanning, Guangxi Province, China\r
+                               Nanning  Guangxi  530007\r
+                               CN\r
+\r
+38-7A-3C   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+387A3C     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+8C-CE-4E   (hex)               Espressif Inc.\r
+8CCE4E     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+B8-2D-28   (hex)               AMPAK Technology,Inc.\r
+B82D28     (base 16)           AMPAK Technology,Inc.\r
+                               3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou,\r
+                               Hsinchu  Hsinchu,Taiwan R.O.C.  30352\r
+                               TW\r
+\r
+C4-41-37   (hex)               Quectel Wireless Solutions Co., Ltd.\r
+C44137     (base 16)           Quectel Wireless Solutions Co., Ltd.\r
+                               7th Floor, Hongye Building, No.1801 Hongmei Road, Xuhui District\r
+                               Shanghai    200233\r
+                               CN\r
+\r
+EC-C8-9C   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+ECC89C     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+                               No.555 Qianmo Road\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+F0-13-C1   (hex)               Hannto Technology Co., Ltd\r
+F013C1     (base 16)           Hannto Technology Co., Ltd\r
+                               Rm 704,No.1,Lane 88,Shengrong Road, Free Trade Pilot Area,\r
+                               Shanghai  Shanghai  200120\r
+                               CN\r
+\r
+F8-0D-AC   (hex)               HP Inc.\r
+F80DAC     (base 16)           HP Inc.\r
+                               10300 Energy Dr\r
+                               Spring  TX  77389\r
+                               US\r
+\r
+88-DA-1A   (hex)               Redpine Signals, Inc.\r
+88DA1A     (base 16)           Redpine Signals, Inc.\r
+                               Plot 87, Sagar Society \r
+                               Hyderabad  AP  500034\r
+                               IN\r
+\r
+40-B5-C1   (hex)               Cisco Systems, Inc\r
+40B5C1     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+E4-47-91   (hex)               Iris ID Systems, Inc.\r
+E44791     (base 16)           Iris ID Systems, Inc.\r
+                               8 Clarke Drive\r
+                               Cranbury    08512\r
+                               US\r
+\r
+00-60-65   (hex)               B&R Industrial Automation GmbH \r
+006065     (base 16)           B&R Industrial Automation GmbH \r
+                               B&R Straße 1\r
+                               Eggelsberg    5142\r
+                               AT\r
+\r
+84-9D-C2   (hex)               Shanghai MXCHIP Information Technology Co., Ltd.\r
+849DC2     (base 16)           Shanghai MXCHIP Information Technology Co., Ltd.\r
+                               9th Floor, No. 5 Building, 2145 Jinshajiang Rd., Putuo District\r
+                               Shanghai    200333\r
+                               CN\r
+\r
+18-45-16   (hex)               Texas Instruments\r
+184516     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+D0-2E-AB   (hex)               Texas Instruments\r
+D02EAB     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+84-54-DF   (hex)               Huawei Device Co., Ltd.\r
+8454DF     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+F0-F7-E7   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F0F7E7     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+E8-84-A5   (hex)               Intel Corporate\r
+E884A5     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+8C-55-BB   (hex)               Songwoo Information & Technology Co., Ltd\r
+8C55BB     (base 16)           Songwoo Information & Technology Co., Ltd\r
+                               24-9, Jinju-daero 404beon-gil, Jinju-si, Gyeongsangnam-do, Korea \r
+                               Jinju  Gyeongsangnam-do  52826\r
+                               KR\r
+\r
+7C-8F-DE   (hex)               DWnet Technologies(Suzhou) Corporation\r
+7C8FDE     (base 16)           DWnet Technologies(Suzhou) Corporation\r
+                               No.8,Tangzhuang Road, Suzhou Industrial Park, Jiangsu, China\r
+                               Suzhou    21500\r
+                               CN\r
+\r
+98-F1-81   (hex)               New H3C Technologies Co., Ltd\r
+98F181     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+90-80-8F   (hex)               Huawei Device Co., Ltd.\r
+90808F     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+40-A9-CF   (hex)               Amazon Technologies Inc.\r
+40A9CF     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+58-95-D8   (hex)               IEEE Registration Authority\r
+5895D8     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+08-38-E6   (hex)               Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
+0838E6     (base 16)           Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
+                               No.19, Gaoxin 4th Road, Wuhan East Lake High-tech Zone, Wuhan\r
+                               Wuhan  Hubei  430000\r
+                               CN\r
+\r
+E8-C2-DD   (hex)               Infinix mobility limited\r
+E8C2DD     (base 16)           Infinix mobility limited\r
+                               RMS 05-15, 13A/F SOUTH TOWER WORLD FINANCE CTR HARBOUR CITY 17 CANTON RD TST KLN HONG KONG\r
+                               HongKong  HongKong  999077\r
+                               HK\r
+\r
+48-D8-90   (hex)               FN-LINK TECHNOLOGY LIMITED\r
+48D890     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
+                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
+                               SHENZHEN  GUANGDONG  518100\r
+                               CN\r
+\r
+78-1F-11   (hex)               RAB Lighting\r
+781F11     (base 16)           RAB Lighting\r
+                               Northvale (NJ) 141 Legrand  Ave. Northvale, NJ 07647\r
+                                Northvale  NJ  07647\r
+                               US\r
+\r
+F8-B9-5A   (hex)               LG Innotek\r
+F8B95A     (base 16)           LG Innotek\r
+                               26, Hanamsandan 5beon-ro\r
+                               Gwangju  Gwangsan-gu  506-731\r
+                               KR\r
+\r
+C4-1C-9C   (hex)               JiQiDao\r
+C41C9C     (base 16)           JiQiDao\r
+                               No.19, SuYuan Avenue, Jiangning District\r
+                               NanJing  Jiangsu  210000\r
+                               CN\r
+\r
+D4-4F-67   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+D44F67     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+B4-FF-98   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+B4FF98     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+84-71-27   (hex)               Silicon Laboratories\r
+847127     (base 16)           Silicon Laboratories\r
+                               400 West Cesar Chavez Street\r
+                               Austin  TX  78701\r
+                               US\r
+\r
+00-26-4E   (hex)               r2p GmbH\r
+00264E     (base 16)           r2p GmbH\r
+                               Norderhofenden 12-13\r
+                               Flensburg    24937\r
+                               DE\r
+\r
+B0-BB-E5   (hex)               Sagemcom Broadband SAS\r
+B0BBE5     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
+\r
+90-B4-DD   (hex)               Private\r
+90B4DD     (base 16)           Private\r
+\r
+C4-18-E9   (hex)               Samsung Electronics Co.,Ltd\r
+C418E9     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+1C-E5-7F   (hex)               Samsung Electronics Co.,Ltd\r
+1CE57F     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+B0-C5-3C   (hex)               Cisco Systems, Inc\r
+B0C53C     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+EC-CE-13   (hex)               Cisco Systems, Inc\r
+ECCE13     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+10-71-00   (hex)               Huawei Device Co., Ltd.\r
+107100     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+8C-FD-DE   (hex)               Sagemcom Broadband SAS\r
+8CFDDE     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
+\r
+A4-68-BC   (hex)               Oakley Inc.\r
+A468BC     (base 16)           Oakley Inc.\r
+                               1 Icon\r
+                               Foothill Ranch  CA  92610\r
+                               US\r
+\r
+60-7E-A4   (hex)               Shanghai Imilab Technology Co.Ltd\r
+607EA4     (base 16)           Shanghai Imilab Technology Co.Ltd\r
+                               29F, A Tower, New Caohejing International Business Center, Guiping Road, Xuhui District\r
+                               Shanghai  Shanghai  200000\r
+                               CN\r
+\r
+24-11-45   (hex)               Xiaomi Communications Co Ltd\r
+241145     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+78-95-EB   (hex)               ITEL MOBILE LIMITED\r
+7895EB     (base 16)           ITEL MOBILE LIMITED\r
+                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
+                               Hong Kong  KOWLOON  999077\r
+                               HK\r
+\r
+1C-9F-4E   (hex)               COOSEA GROUP (HK) COMPANY LIMITED\r
+1C9F4E     (base 16)           COOSEA GROUP (HK) COMPANY LIMITED\r
+                               UNIT 5-6 16/F MULTIFIELD PLAZA 3-7A PRAT AVENUE TSIMSHATSUI\r
+                               KL    999077\r
+                               HK\r
+\r
+14-AB-02   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+14AB02     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+BC-5B-D5   (hex)               ARRIS Group, Inc.\r
+BC5BD5     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+08-55-31   (hex)               Routerboard.com\r
+085531     (base 16)           Routerboard.com\r
+                               Mikrotikls SIA\r
+                               Riga  Riga  LV1009\r
+                               LV\r
+\r
+3C-61-05   (hex)               Espressif Inc.\r
+3C6105     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+24-06-AA   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+2406AA     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+84-30-95   (hex)               Hon Hai Precision IND.CO.,LTD\r
+843095     (base 16)           Hon Hai Precision IND.CO.,LTD\r
+                               No. 66 Chung Shan Road TU-Cheng Industrial district TAIPEI TAIWAN \r
+                               TAIPEI  TAIWAN  33859\r
+                               CN\r
+\r
+08-65-F0   (hex)               JM Zengge Co., Ltd\r
+0865F0     (base 16)           JM Zengge Co., Ltd\r
+                               5/F Torch building, Jinou Road#288, Jianghai District\r
+                               Jiangmen  Guangdong  529080\r
+                               CN\r
+\r
+AC-47-1B   (hex)               Huawei Device Co., Ltd.\r
+AC471B     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+00-31-92   (hex)               TP-Link Corporation Limited\r
+003192     (base 16)           TP-Link Corporation Limited\r
+                               Room 901,9/F.New East Ocean Centre, 9 Science Museum Road\r
+                                Tsim Sha Tsui  Kowloon  999077\r
+                               HK\r
+\r
+A4-CC-B9   (hex)               Realme Chongqing Mobile Telecommunications Corp.,Ltd.\r
+A4CCB9     (base 16)           Realme Chongqing Mobile Telecommunications Corp.,Ltd.\r
+                               No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing.\r
+                               Chongqing   China  401120\r
+                               CN\r
+\r
+90-FF-D6   (hex)               Honor Device Co., Ltd.\r
+90FFD6     (base 16)           Honor Device Co., Ltd.\r
+                               A1701, Block AB, Building 1, Tianan Yungu Phase I, Gangtou Community, Bantian Street\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+6C-B8-81   (hex)               zte corporation\r
+6CB881     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+98-9A-B9   (hex)               zte corporation\r
+989AB9     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+00-8A-55   (hex)               Huawei Device Co., Ltd.\r
+008A55     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+64-A2-8A   (hex)               Huawei Device Co., Ltd.\r
+64A28A     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+B4-56-E3   (hex)               Apple, Inc.\r
+B456E3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+4C-20-B8   (hex)               Apple, Inc.\r
+4C20B8     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+14-88-E6   (hex)               Apple, Inc.\r
+1488E6     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+EC-0D-E4   (hex)               Amazon Technologies Inc.\r
+EC0DE4     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+BC-0F-9A   (hex)               D-Link International\r
+BC0F9A     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+B0-45-30   (hex)               BSkyB Ltd\r
+B04530     (base 16)           BSkyB Ltd\r
+                               130 Kings Road\r
+                               Brentwood  Essex  08854\r
+                               GB\r
+\r
+6C-A0-B4   (hex)               BSkyB Ltd\r
+6CA0B4     (base 16)           BSkyB Ltd\r
+                               130 Kings Road\r
+                               Brentwood  Essex  08854\r
+                               GB\r
+\r
+94-7B-BE   (hex)               Ubicquia LLC\r
+947BBE     (base 16)           Ubicquia LLC\r
+                               BoA Building–Suite 1750, 401 E. Las Olas Boulevard\r
+                               Fort Lauderdale  FL  33301\r
+                               US\r
+\r
+24-64-9F   (hex)               Huawei Device Co., Ltd.\r
+24649F     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+0C-17-73   (hex)               Huawei Device Co., Ltd.\r
+0C1773     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+E8-1E-92   (hex)               Huawei Device Co., Ltd.\r
+E81E92     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+88-8E-68   (hex)               Huawei Device Co., Ltd.\r
+888E68     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+80-74-84   (hex)               ALL Winner (Hong Kong) Limited\r
+807484     (base 16)           ALL Winner (Hong Kong) Limited\r
+                               Unit No.1301,13F,Sunbeam Plaza,1155 Canton Road,Mongkok,Kowloon,Hong Kong\r
+                               Hong Kong    999077\r
+                               CN\r
+\r
+8C-AE-49   (hex)               IEEE Registration Authority\r
+8CAE49     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+74-95-EC   (hex)               ALPSALPINE CO,.LTD\r
+7495EC     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-21-4F   (hex)               ALPSALPINE CO,.LTD\r
+00214F     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+04-98-F3   (hex)               ALPSALPINE CO,.LTD\r
+0498F3     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1 NISHIDA\r
+                               KAKUDA  MIYAGI PREF  9876-8501\r
+                               JP\r
+\r
+64-D4-BD   (hex)               ALPSALPINE CO,.LTD\r
+64D4BD     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
+                               JP\r
+\r
+34-C7-31   (hex)               ALPSALPINE CO,.LTD\r
+34C731     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
+00-06-F5   (hex)               ALPSALPINE CO,.LTD\r
+0006F5     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
+00-07-04   (hex)               ALPSALPINE CO,.LTD\r
+000704     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
+00-06-F7   (hex)               ALPSALPINE CO,.LTD\r
+0006F7     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
+BC-42-8C   (hex)               ALPSALPINE CO,.LTD\r
+BC428C     (base 16)           ALPSALPINE CO,.LTD\r
+                               nishida  6-1 \r
+                               Kakuda-City  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
 9C-FF-C2   (hex)               AVI Systems GmbH\r
 9CFFC2     (base 16)           AVI Systems GmbH\r
                                Dr. Franz Wilhelmstraße 2A\r
@@ -35636,36 +36074,12 @@ C80873     (base 16)          Ruckus Wireless
                                Bayan Lepas  Penang  11900\r
                                MY\r
 \r
-04-76-6E   (hex)               ALPS ELECTRIC CO., LTD.\r
-04766E     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
-AC-7A-4D   (hex)               ALPS ELECTRIC CO., LTD.\r
-AC7A4D     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
-                               JP\r
-\r
 00-1B-B5   (hex)               Cherry GmbH\r
 001BB5     (base 16)           Cherry GmbH\r
                                Cherrystraße 1\r
                                Auerbach i. d. Opf.  Bayern  D-91275\r
                                DE\r
 \r
-00-26-43   (hex)               ALPS ELECTRIC CO., LTD.\r
-002643     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-38-C0-96   (hex)               ALPS ELECTRIC CO., LTD.\r
-38C096     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
-                               JP\r
-\r
 D0-51-57   (hex)               LEAX Arkivator Telecom\r
 D05157     (base 16)           LEAX Arkivator Telecom\r
                                NanShan District YueHaiMen Street\r
@@ -38207,12 +38621,6 @@ F079E8     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
                                DONG GUAN  GUANG DONG  523860\r
                                CN\r
 \r
-78-32-1B   (hex)               D-Link International\r
-78321B     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 60-18-03   (hex)               Daikin Air-conditioning (Shanghai) Co., Ltd.\r
 601803     (base 16)           Daikin Air-conditioning (Shanghai) Co., Ltd.\r
                                318 Shen Fu Road, Xin Zhuang Industry Zone, Shanghai, 201108, China\r
@@ -54449,12 +54857,6 @@ D4AAFF     (base 16)           MICRO WORLD
                                Seoul    140-847\r
                                KR\r
 \r
-00-1B-2E   (hex)               Sinkyo Electron Inc\r
-001B2E     (base 16)           Sinkyo Electron Inc\r
-                               3-3-21 asahigaoka\r
-                               hino-city  Tokyo  191-0065\r
-                               JP\r
-\r
 00-1B-5F   (hex)               Alien Technology\r
 001B5F     (base 16)           Alien Technology\r
                                18220 Butterfield Blvd.\r
@@ -66326,12 +66728,6 @@ AC4A67     (base 16)           Cisco Systems, Inc
                                Sunnyvale  CA  94089\r
                                US\r
 \r
-30-B2-16   (hex)               ABB Power Grids Germany AG – Grid Automation\r
-30B216     (base 16)           ABB Power Grids Germany AG – Grid Automation\r
-                               Kallstadter Strasse 1\r
-                               Mannheim    68309\r
-                               DE\r
-\r
 00-09-91   (hex)               Intelligent Platforms, LLC.\r
 000991     (base 16)           Intelligent Platforms, LLC.\r
                                2500 Austin Drive\r
@@ -67661,18 +68057,72 @@ B04414     (base 16)          New H3C Technologies Co., Ltd
                                Dongguan  Guangdong  523808\r
                                CN\r
 \r
-5C-34-00   (hex)               HISENSE VISUAL TECHNOLOGY CO.,LTD\r
-5C3400     (base 16)           HISENSE VISUAL TECHNOLOGY CO.,LTD\r
-                               Qianwangang Road 218\r
-                               Qingdao  Shandong  266510\r
-                               CN\r
-\r
 78-45-58   (hex)               Ubiquiti Networks Inc.\r
 784558     (base 16)           Ubiquiti Networks Inc.\r
                                685 Third Avenue, 27th Floor\r
                                New York  NY  10017\r
                                US\r
 \r
+64-F9-47   (hex)               Senscomm Semiconductor Co., Ltd.\r
+64F947     (base 16)           Senscomm Semiconductor Co., Ltd.\r
+                               Room 303-309, 3rd Floor International Building, NO.2 Suzhou Avenue West\r
+                               Suzhou  Jiangsu  215000\r
+                               CN\r
+\r
+DC-00-B0   (hex)               FREEBOX SAS\r
+DC00B0     (base 16)           FREEBOX SAS\r
+                               16 rue de la Ville l'Eveque\r
+                               PARIS  IdF  75008\r
+                               FR\r
+\r
+70-74-14   (hex)               Murata Manufacturing Co., Ltd.\r
+707414     (base 16)           Murata Manufacturing Co., Ltd.\r
+                               1-10-1, Higashikotari\r
+                               Nagaokakyo-shi  Kyoto  617-8555\r
+                               JP\r
+\r
+A0-76-4E   (hex)               Espressif Inc.\r
+A0764E     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+B4-FB-E3   (hex)               AltoBeam (China) Inc.\r
+B4FBE3     (base 16)           AltoBeam (China) Inc.\r
+                               B808, Tsinghua Tongfang Hi-Tech Plaza, Haidian\r
+                               Beijing  Beijing  100083\r
+                               CN\r
+\r
+18-87-40   (hex)               Xiaomi Communications Co Ltd\r
+188740     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+34-1C-F0   (hex)               Xiaomi Communications Co Ltd\r
+341CF0     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+10-D7-B0   (hex)               Sagemcom Broadband SAS\r
+10D7B0     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
+\r
+44-59-43   (hex)               zte corporation\r
+445943     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+34-36-54   (hex)               zte corporation\r
+343654     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
 74-8F-3C   (hex)               Apple, Inc.\r
 748F3C     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
@@ -67685,42 +68135,582 @@ B04414     (base 16)         New H3C Technologies Co., Ltd
                                Cupertino  CA  95014\r
                                US\r
 \r
-44-59-43   (hex)               zte corporation\r
-445943     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
+6C-09-BF   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+6C09BF     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
                                CN\r
 \r
-34-36-54   (hex)               zte corporation\r
-343654     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
+30-AF-CE   (hex)               vivo Mobile Communication Co., Ltd.\r
+30AFCE     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
                                CN\r
 \r
-64-F9-47   (hex)               Senscomm Semiconductor Co., Ltd.\r
-64F947     (base 16)           Senscomm Semiconductor Co., Ltd.\r
-                               Room 303-309, 3rd Floor International Building, NO.2 Suzhou Avenue West\r
-                               Suzhou  Jiangsu  215000\r
+FC-6D-D1   (hex)               APRESIA Systems, Ltd.\r
+FC6DD1     (base 16)           APRESIA Systems, Ltd.\r
+                               Tsukuba Network Technical Center, Kidamari 3550\r
+                               Tsuchiura-shi  Ibaraki-ken  300-0026\r
+                               JP\r
+\r
+80-C9-55   (hex)               Redpine Signals, Inc.\r
+80C955     (base 16)           Redpine Signals, Inc.\r
+                               Plot 87, Sagar Society \r
+                               Hyderabad  AP  500034\r
+                               IN\r
+\r
+CC-4F-5C   (hex)               IEEE Registration Authority\r
+CC4F5C     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+30-B2-16   (hex)               Hitachi ABB Power Grids – Grid Automation\r
+30B216     (base 16)           Hitachi ABB Power Grids – Grid Automation\r
+                               Kallstadter Strasse 1\r
+                               Mannheim    68309\r
+                               DE\r
+\r
+4C-6D-58   (hex)               Juniper Networks\r
+4C6D58     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+5C-ED-8C   (hex)               Hewlett Packard Enterprise\r
+5CED8C     (base 16)           Hewlett Packard Enterprise\r
+                               8000 Foothills Blvd.\r
+                               Roseville  CA  95747\r
+                               US\r
+\r
+30-D0-42   (hex)               Dell Inc.\r
+30D042     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
+\r
+C0-C9-E3   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+C0C9E3     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
                                CN\r
 \r
-DC-00-B0   (hex)               FREEBOX SAS\r
-DC00B0     (base 16)           FREEBOX SAS\r
-                               16 rue de la Ville l'Eveque\r
-                               PARIS  IdF  75008\r
+F8-8C-21   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+F88C21     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+C4-27-8C   (hex)               Huawei Device Co., Ltd.\r
+C4278C     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+80-8F-E8   (hex)               Intelbras\r
+808FE8     (base 16)           Intelbras\r
+                               BR 101, km 210, S/N°\r
+                               São José  Santa Catarina  88104800\r
+                               BR\r
+\r
+18-CC-18   (hex)               Intel Corporate\r
+18CC18     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+7C-73-EB   (hex)               Huawei Device Co., Ltd.\r
+7C73EB     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+E4-8F-1D   (hex)               Huawei Device Co., Ltd.\r
+E48F1D     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+84-E3-42   (hex)               Tuya?HK?Limietd\r
+84E342     (base 16)           Tuya?HK?Limietd\r
+                               FLAT/RM 806 BLK ? 8/F CHEUNG SHA WAN PLAZA 833 CHEUNG SHA WAN ROAD KL\r
+                               hongkong  Hong Kong  999077\r
+                               CN\r
+\r
+C0-3C-59   (hex)               Intel Corporate\r
+C03C59     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+FC-CD-2F   (hex)               IEEE Registration Authority\r
+FCCD2F     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+94-B2-71   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+94B271     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+78-05-8C   (hex)               mMax Communications, Inc.\r
+78058C     (base 16)           mMax Communications, Inc.\r
+                               5151 California Ave., Suite 100\r
+                               Irvine  CA  92617\r
+                               US\r
+\r
+C4-A7-2B   (hex)               SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD\r
+C4A72B     (base 16)           SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD\r
+                               Unit East Block22-24/F,Skyworth semiconductor design  Bldg., Gaoxin Ave.4.S.,Nanshan District,Shenzhen,China\r
+                               SHENZHEN  GUANGDONG  518057\r
+                               CN\r
+\r
+CC-F5-5F   (hex)               E FOCUS INSTRUMENTS INDIA PRIVATE LIMITED\r
+CCF55F     (base 16)           E FOCUS INSTRUMENTS INDIA PRIVATE LIMITED\r
+                               PLOT NO 21, 1ST FLOOR, NO 22, SAMAYAPURAM MAIN ROAD PORUR\r
+                               CHENNAI  TAMIL NADU  600116\r
+                               IN\r
+\r
+D0-C3-1E   (hex)               JUNGJIN Electronics Co.,Ltd\r
+D0C31E     (base 16)           JUNGJIN Electronics Co.,Ltd\r
+                               41-11, Yangjipyeon-ro\r
+                               Uiwang-si  Gyeonggi-do  16007\r
+                               KR\r
+\r
+14-13-33   (hex)               AzureWave Technology Inc.\r
+141333     (base 16)           AzureWave Technology Inc.\r
+                               8F., No. 94, Baozhong Rd.\r
+                               New Taipei City  Taiwan  231\r
+                               TW\r
+\r
+A4-17-8B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+A4178B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+5C-34-00   (hex)               Hisense Electric Co.,Ltd\r
+5C3400     (base 16)           Hisense Electric Co.,Ltd\r
+                               Qianwangang Road 218\r
+                               Qingdao  Shandong  266510\r
+                               CN\r
+\r
+4C-3B-DF   (hex)               Microsoft Corporation\r
+4C3BDF     (base 16)           Microsoft Corporation\r
+                               One Microsoft Way\r
+                               REDMOND  WA  98052\r
+                               US\r
+\r
+08-7C-39   (hex)               Amazon Technologies Inc.\r
+087C39     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+D8-10-CB   (hex)               Andrea Informatique\r
+D810CB     (base 16)           Andrea Informatique\r
+                               30 Rue Jules Guesde\r
+                               Paris    75014\r
                                FR\r
 \r
-70-74-14   (hex)               Murata Manufacturing Co., Ltd.\r
-707414     (base 16)           Murata Manufacturing Co., Ltd.\r
-                               1-10-1, Higashikotari\r
-                               Nagaokakyo-shi  Kyoto  617-8555\r
+FC-19-28   (hex)               Actions Microelectronics Co., Ltd\r
+FC1928     (base 16)           Actions Microelectronics Co., Ltd\r
+                               201, No 9 Building, Software Park,Kejizhonger Rd.,\r
+                               Shenzhen  Gangdong  518057\r
+                               CN\r
+\r
+3C-D2-E5   (hex)               New H3C Technologies Co., Ltd\r
+3CD2E5     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+B0-98-BC   (hex)               Huawei Device Co., Ltd.\r
+B098BC     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+24-01-6F   (hex)               Huawei Device Co., Ltd.\r
+24016F     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+D0-59-19   (hex)               zte corporation\r
+D05919     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+E0-91-3C   (hex)               Kyeungin CNS Co., Ltd.\r
+E0913C     (base 16)           Kyeungin CNS Co., Ltd.\r
+                               13, Gyeongin-ro, Sosa-gu\r
+                               Bucheon-si  Gyeonggi-do  14730\r
+                               KR\r
+\r
+00-B8-81   (hex)               New platforms LLC\r
+00B881     (base 16)           New platforms LLC\r
+                               Varshavskoe shosse, 35, Bld. 1\r
+                               Moscow    117105\r
+                               RU\r
+\r
+00-1B-2E   (hex)               Sinkyo Electron Inc\r
+001B2E     (base 16)           Sinkyo Electron Inc\r
+                               1-22-19 Daimachi\r
+                               Hachioji-city   Tokyo  193-0931\r
                                JP\r
 \r
-A0-76-4E   (hex)               Espressif Inc.\r
-A0764E     (base 16)           Espressif Inc.\r
+C4-37-72   (hex)               Virtuozzo International GmbH\r
+C43772     (base 16)           Virtuozzo International GmbH\r
+                               Vordergasse 59\r
+                               Schaffhausen    8200\r
+                               CH\r
+\r
+CC-3B-27   (hex)               TECNO MOBILE LIMITED\r
+CC3B27     (base 16)           TECNO MOBILE LIMITED\r
+                               ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG\r
+                               Hong Kong  Hong Kong  999077\r
+                               HK\r
+\r
+08-58-A5   (hex)               Beijing Vrv Software Corpoaration Limited.\r
+0858A5     (base 16)           Beijing Vrv Software Corpoaration Limited.\r
+                               Room 1602, block C, Zhongguancun Science and technology development building, 34 Zhongguancun South Street\r
+                               Beijing  Beijing  100000\r
+                               CN\r
+\r
+98-3F-60   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+983F60     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+C0-3F-DD   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C03FDD     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+30-32-35   (hex)               Qingdao Intelligent&Precise Electronics Co.,Ltd.\r
+303235     (base 16)           Qingdao Intelligent&Precise Electronics Co.,Ltd.\r
+                               No.218 Qianwangang Road\r
+                               Qingdao  Shangdong  266510\r
+                               CN\r
+\r
+E0-E2-E6   (hex)               Espressif Inc.\r
+E0E2E6     (base 16)           Espressif Inc.\r
                                Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
                                Shanghai  Shanghai  201203\r
                                CN\r
 \r
+9C-73-70   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+9C7370     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+58-24-29   (hex)               Google, Inc.\r
+582429     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+E8-0A-EC   (hex)               Jiangsu Hengtong Optic-Electric Co., LTD\r
+E80AEC     (base 16)           Jiangsu Hengtong Optic-Electric Co., LTD\r
+                               88 Hengtong Dadao, Qidu Town, Wujiang District\r
+                               Suzhou  Jiangsu Province  215200\r
+                               CN\r
+\r
+C4-DE-7B   (hex)               Huawei Device Co., Ltd.\r
+C4DE7B     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+84-1B-77   (hex)               Intel Corporate\r
+841B77     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+7C-C2-94   (hex)               Beijing Xiaomi Mobile Software Co., Ltd\r
+7CC294     (base 16)           Beijing Xiaomi Mobile Software Co., Ltd\r
+                               The Rainbow City Office Building, 68 Qinghe Middle Street Haidian District\r
+                               Beijing  Beijing  100085\r
+                               CN\r
+\r
+40-D4-BD   (hex)               SK Networks Service CO., LTD.\r
+40D4BD     (base 16)           SK Networks Service CO., LTD.\r
+                               120, Jangan-ro, Jangan-gu\r
+                               Suwon-si  Gyeonggi-do  16312\r
+                               KR\r
+\r
+68-D4-8B   (hex)               Hailo Technologies Ltd.\r
+68D48B     (base 16)           Hailo Technologies Ltd.\r
+                               94 Yigal Alon\r
+                               Tel Aviv    6789139\r
+                               IL\r
+\r
+6C-1A-75   (hex)               Huawei Device Co., Ltd.\r
+6C1A75     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+6C-76-37   (hex)               Huawei Device Co., Ltd.\r
+6C7637     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+18-EE-86   (hex)               Novatel Wireless Solutions, Inc.\r
+18EE86     (base 16)           Novatel Wireless Solutions, Inc.\r
+                               9710 Scranton Rd., Suite 200\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+A0-9F-10   (hex)               SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+A09F10     (base 16)           SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+                               NO.268? Fuqian Rd, Jutang community, Guanlan Town, Longhua New district\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
+\r
+20-1B-88   (hex)               Dongguan Liesheng Electronic Co., Ltd.\r
+201B88     (base 16)           Dongguan Liesheng Electronic Co., Ltd.\r
+                               F5, Building B, North Block, Gaosheng Tech Park, No. 84 Zhongli Road, Nancheng District, Dongguan Ci\r
+                               dongguan   guangdong  523000\r
+                               CN\r
+\r
+24-94-93   (hex)               FibRSol Global Network Limited\r
+249493     (base 16)           FibRSol Global Network Limited\r
+                               17, Deep vihar, Vikas Nagar,, Near Mayank hospital,, Uttam Nagar,\r
+                               New Delhi  Delhi  110059\r
+                               IN\r
+\r
+28-D0-44   (hex)               Shenzhen Xinyin technology company\r
+28D044     (base 16)           Shenzhen Xinyin technology company\r
+                               2/F, Building C, Jianxing Technology Building, Shahe West Road, Xili Street, Nanshan District \r
+                               Shenzhen  Guangdong  518055\r
+                               CN\r
+\r
+A8-40-7D   (hex)               GD Midea Air-Conditioning Equipment Co.,Ltd.\r
+A8407D     (base 16)           GD Midea Air-Conditioning Equipment Co.,Ltd.\r
+                               Midea Global Innovation Center,Beijiao Town,Shunde\r
+                               Foshan  Guangdong  528311\r
+                               CN\r
+\r
+FC-4B-57   (hex)               Peerless Instrument Division of Curtiss-Wright \r
+FC4B57     (base 16)           Peerless Instrument Division of Curtiss-Wright \r
+                               1966D Broadhollow Road\r
+                               East Farmingdale  NY  11735\r
+                               US\r
+\r
+5C-10-C5   (hex)               Samsung Electronics Co.,Ltd\r
+5C10C5     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+E8-EB-34   (hex)               Cisco Systems, Inc\r
+E8EB34     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+58-60-D8   (hex)               ARRIS Group, Inc.\r
+5860D8     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+9C-9A-C0   (hex)               LEGO System A/S\r
+9C9AC0     (base 16)           LEGO System A/S\r
+                               Aastvej 1\r
+                               Billund    DK-7190\r
+                               DK\r
+\r
+3C-BD-C5   (hex)               Arcadyan Corporation\r
+3CBDC5     (base 16)           Arcadyan Corporation\r
+                               No.8, Sec.2, Guangfu Rd.\r
+                               Hsinchu City  Hsinchu  30071\r
+                               TW\r
+\r
+DC-8C-1B   (hex)               vivo Mobile Communication Co., Ltd.\r
+DC8C1B     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
+                               CN\r
+\r
+A8-DA-0C   (hex)               SERVERCOM (INDIA) PRIVATE LIMITED\r
+A8DA0C     (base 16)           SERVERCOM (INDIA) PRIVATE LIMITED\r
+                               E-43/1 OKHLA INDUSTRIAL AREA PHASE-II NEW DELHI SOUTH DELHI\r
+                               NEW DELHI    110001\r
+                               IN\r
+\r
+F8-53-29   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F85329     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+50-A5-DC   (hex)               ARRIS Group, Inc.\r
+50A5DC     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+74-B7-B3   (hex)               Shenzhen YOUHUA Technology Co., Ltd\r
+74B7B3     (base 16)           Shenzhen YOUHUA Technology Co., Ltd\r
+                               Room 407 Shenzhen University-town Business Park,Lishan Road,Taoyuan Street,Nanshan District\r
+                               Shenzhen  Guangdong  518055\r
+                               CN\r
+\r
+88-15-C5   (hex)               Huawei Device Co., Ltd.\r
+8815C5     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+B4-1B-B0   (hex)               Apple, Inc.\r
+B41BB0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+58-D3-49   (hex)               Apple, Inc.\r
+58D349     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+F4-34-F0   (hex)               Apple, Inc.\r
+F434F0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+B0-8C-75   (hex)               Apple, Inc.\r
+B08C75     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+A4-AA-FE   (hex)               Huawei Device Co., Ltd.\r
+A4AAFE     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+F8-3B-7E   (hex)               Huawei Device Co., Ltd.\r
+F83B7E     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+9C-28-B3   (hex)               Apple, Inc.\r
+9C28B3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+A0-78-17   (hex)               Apple, Inc.\r
+A07817     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+5C-87-30   (hex)               Apple, Inc.\r
+5C8730     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+DC-9B-D6   (hex)               TCT mobile ltd\r
+DC9BD6     (base 16)           TCT mobile ltd\r
+                               No.86 hechang 7th road, zhongkai, Hi-Tech District\r
+                               Hui Zhou  Guang Dong  516006\r
+                               CN\r
+\r
+74-EC-B2   (hex)               Amazon Technologies Inc.\r
+74ECB2     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+70-40-FF   (hex)               Huawei Device Co., Ltd.\r
+7040FF     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+34-D6-93   (hex)               Huawei Device Co., Ltd.\r
+34D693     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+E0-1F-ED   (hex)               Nokia Shanghai Bell Co., Ltd.\r
+E01FED     (base 16)           Nokia Shanghai Bell Co., Ltd.\r
+                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai \r
+                               Shanghai    201206\r
+                               CN\r
+\r
+14-6B-9A   (hex)               zte corporation\r
+146B9A     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+78-32-1B   (hex)               D-Link International\r
+78321B     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+04-E7-7E   (hex)               We Corporation Inc.\r
+04E77E     (base 16)           We Corporation Inc.\r
+                               201, 33, Deokcheon-ro, Manan-gu\r
+                               Anyang-si  Gyeonggi-do  14088\r
+                               KR\r
+\r
+4C-52-EC   (hex)               SOLARWATT GmbH\r
+4C52EC     (base 16)           SOLARWATT GmbH\r
+                               Maria-Reiche-Str. 2a\r
+                               Dresden    01109\r
+                               DE\r
+\r
+30-D9-41   (hex)               Raydium Semiconductor Corp.\r
+30D941     (base 16)           Raydium Semiconductor Corp.\r
+                               2F, No. 23, LiHsin Rd., Hsinchu Science Park\r
+                               Hsinchu, Taiwan, R.O.C.    TW 300\r
+                               TW\r
+\r
+00-26-43   (hex)               ALPSALPINE CO,.LTD\r
+002643     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+38-C0-96   (hex)               ALPSALPINE CO,.LTD\r
+38C096     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
+                               JP\r
+\r
+AC-7A-4D   (hex)               ALPSALPINE CO,.LTD\r
+AC7A4D     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
+                               JP\r
+\r
+04-76-6E   (hex)               ALPSALPINE CO,.LTD\r
+04766E     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
 84-80-94   (hex)               Meter, Inc.\r
 848094     (base 16)           Meter, Inc.\r
                                148 Townsend St\r
@@ -67757,9 +68747,6 @@ ACA88E     (base 16)            SHARP Corporation
                                KYOTO  KYOTO  601-8501\r
                                JP\r
 \r
-F0-4F-7C   (hex)               Private\r
-F04F7C     (base 16)           Private\r
-\r
 70-54-25   (hex)               ARRIS Group, Inc.\r
 705425     (base 16)           ARRIS Group, Inc.\r
                                6450 Sequence Drive\r
@@ -67778,9 +68765,6 @@ F04F7C     (base 16)            Private
                                Dongguan  Guangdong  523808\r
                                CN\r
 \r
-F0-A2-25   (hex)               Private\r
-F0A225     (base 16)           Private\r
-\r
 50-A1-32   (hex)               Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
 50A132     (base 16)           Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
                                Chudong science and technology park, 111 shaxin road, tangxia town,\r
@@ -68096,12 +69080,6 @@ C4AC59     (base 16)           Murata Manufacturing Co., Ltd.
                                Nagaokakyo-shi  Kyoto  617-8555\r
                                JP\r
 \r
-58-16-D7   (hex)               ALPS ELECTRIC CO., LTD.\r
-5816D7     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               nishida  6-1 \r
-                               Kakuda-City  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 FC-A4-7A   (hex)               IEEE Registration Authority\r
 FCA47A     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
@@ -69215,24 +70193,6 @@ D4C93C     (base 16)           Cisco Systems, Inc
                                Hangzhou  Zhejiang  310053\r
                                CN\r
 \r
-00-24-33   (hex)               ALPS ELECTRIC CO., LTD.\r
-002433     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-00-23-06   (hex)               ALPS ELECTRIC CO., LTD.\r
-002306     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-B4-EC-02   (hex)               ALPS ELECTRIC CO., LTD.\r
-B4EC02     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 64-60-38   (hex)               Hirschmann Automation and Control GmbH\r
 646038     (base 16)           Hirschmann Automation and Control GmbH\r
                                Stuttgarter Straße 45-51\r
@@ -69251,30 +70211,6 @@ CCD39D     (base 16)           IEEE Registration Authority
                                Piscataway  NJ  08554\r
                                US\r
 \r
-E0-75-0A   (hex)               ALPS ELECTRIC CO., LTD.\r
-E0750A     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               kakuda-City    981-1595\r
-                               US\r
-\r
-00-19-C1   (hex)               ALPS ELECTRIC CO., LTD.\r
-0019C1     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-00-16-FE   (hex)               ALPS ELECTRIC CO., LTD.\r
-0016FE     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-9C-8D-7C   (hex)               ALPS ELECTRIC CO., LTD.\r
-9C8D7C     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 D4-25-CC   (hex)               IEEE Registration Authority\r
 D425CC     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
@@ -69287,18 +70223,6 @@ D425CC     (base 16)           IEEE Registration Authority
                                Walnut  CA  91789\r
                                US\r
 \r
-BC-75-36   (hex)               ALPS ELECTRIC CO., LTD.\r
-BC7536     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               nishida  6-1 \r
-                               Kakuda-City  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
-E0-AE-5E   (hex)               ALPS ELECTRIC CO., LTD.\r
-E0AE5E     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-3-36 Furukawanakazato,\r
-                               Osaki  Miyagi-pref  989-6181\r
-                               JP\r
-\r
 D4-B7-61   (hex)               Sichuan AI-Link Technology Co., Ltd.\r
 D4B761     (base 16)           Sichuan AI-Link Technology Co., Ltd.\r
                                Anzhou,Industrial Park\r
@@ -70481,12 +71405,6 @@ A4EA8E     (base 16)           Extreme Networks, Inc.
                                Dongguan, Guangdong    523770\r
                                CN\r
 \r
-0C-B6-D2   (hex)               D-Link International\r
-0CB6D2     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 78-29-ED   (hex)               ASKEY COMPUTER CORP\r
 7829ED     (base 16)           ASKEY COMPUTER CORP\r
                                10F,No.119,JIANKANG RD,ZHONGHE DIST\r
@@ -71369,12 +72287,6 @@ B4DEDF     (base 16)           zte corporation
                                shenzhen  guangdong  518057\r
                                CN\r
 \r
-28-3B-82   (hex)               D-Link International\r
-283B82     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 D4-90-9C   (hex)               Apple, Inc.\r
 D4909C     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
@@ -84290,12 +85202,6 @@ B4A5A9     (base 16)           MODI GmbH
                                REICHSHOF-Sinspert    51580\r
                                DE\r
 \r
-E8-C3-20   (hex)               Austco Communication Systems Pty Ltd\r
-E8C320     (base 16)           Austco Communication Systems Pty Ltd\r
-                               40 O'Malley Street\r
-                               Osborne Park  Western Australia  6017\r
-                               AU\r
-\r
 C4-36-DA   (hex)               Rusteletech Ltd.\r
 C436DA     (base 16)           Rusteletech Ltd.\r
                                Ordzhonikidze Str. 11, Bldg. 40, Off. 15 \r
@@ -86948,12 +87854,6 @@ D8D67E     (base 16)           GSK CNC EQUIPMENT CO.,LTD
                                San Giuliano Milanese  Milano  20098\r
                                IT\r
 \r
-00-23-86   (hex)               Tour & Andersson AB\r
-002386     (base 16)           Tour & Andersson AB\r
-                               Annelund\r
-                               Ljung    524 80\r
-                               US\r
-\r
 00-23-83   (hex)               InMage Systems Inc\r
 002383     (base 16)           InMage Systems Inc\r
                                3255-1 Scott Blvd, #104\r
@@ -87020,12 +87920,6 @@ D8D67E     (base 16)           GSK CNC EQUIPMENT CO.,LTD
                                Beijing    100091\r
                                CN\r
 \r
-00-23-A7   (hex)               Redpine Signals, Inc.\r
-0023A7     (base 16)           Redpine Signals, Inc.\r
-                               Plot 87, Sagar Society\r
-                               Hyderabad  AP  500034\r
-                               IN\r
-\r
 00-23-9B   (hex)               Elster Solutions, LLC\r
 00239B     (base 16)           Elster Solutions, LLC\r
                                208 South Rogers Lane\r
@@ -93575,12 +94469,6 @@ D8D67E     (base 16)           GSK CNC EQUIPMENT CO.,LTD
                                    \r
                                JP\r
 \r
-00-07-89   (hex)               Allradio Co., Ltd\r
-000789     (base 16)           Allradio Co., Ltd\r
-                               861-5, Gwanyang-Dong, Dongan-Gu,\r
-                               Anyang-si, Gyeonggi-do,    430-803\r
-                               KR\r
-\r
 00-07-B9   (hex)               Ginganet Corporation\r
 0007B9     (base 16)           Ginganet Corporation\r
                                Kintetsu Shin Namba Building\r
@@ -101738,18 +102626,657 @@ D0D23C     (base 16)               Apple, Inc.
                                Piscataway  NJ  08554\r
                                US\r
 \r
+D4-48-2D   (hex)               Shenzhen Deejoy Lighting Technology Co.,Ltd.\r
+D4482D     (base 16)           Shenzhen Deejoy Lighting Technology Co.,Ltd.\r
+                               3rd Floor, Building B3, Xujingchang Industrial Park,Xinhe Community Fuyong Town,Baoan District\r
+                               Shenzhen  Guangdong  518103\r
+                               CN\r
+\r
 D8-F8-AF   (hex)               DAONTEC\r
 D8F8AF     (base 16)           DAONTEC\r
                                219, Gasan digital 1-ro\r
                                Seoul    KS013\r
                                KR\r
 \r
-D4-48-2D   (hex)               Shenzhen Deejoy Lighting Technology Co.,Ltd.\r
-D4482D     (base 16)           Shenzhen Deejoy Lighting Technology Co.,Ltd.\r
-                               3rd Floor, Building B3, Xujingchang Industrial Park,Xinhe Community Fuyong Town,Baoan District\r
-                               Shenzhen  Guangdong  518103\r
+40-8C-4C   (hex)               Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
+408C4C     (base 16)           Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
+                               Chudong science and technology park, 111 shaxin road, tangxia town,\r
+                               dongguan city  guangdong province  523710\r
+                               CN\r
+\r
+6C-AD-AD   (hex)               CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+6CADAD     (base 16)           CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
+                               Chongqing  Chongqing  401332\r
+                               CN\r
+\r
+CC-E0-DA   (hex)               Baidu Online Network Technology (Beijing) Co., Ltd\r
+CCE0DA     (base 16)           Baidu Online Network Technology (Beijing) Co., Ltd\r
+                               Baidu Campus, No.10 Shangdi 10th Street, Haidian District\r
+                                Beijing    100085\r
+                               CN\r
+\r
+14-1B-30   (hex)               Shenzhen Yipingfang Network Technology Co., Ltd.\r
+141B30     (base 16)           Shenzhen Yipingfang Network Technology Co., Ltd.\r
+                               21 / F, Kangjia R & D building, No.28, Keji South 12th Road, Nanshan District, Shenzhen City, Guangdong Province, China\r
+                               Shenzhen  Nanshan District  518000\r
+                               CN\r
+\r
+F4-6F-ED   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+F46FED     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+94-B9-7E   (hex)               Espressif Inc.\r
+94B97E     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+A8-30-1C   (hex)               Qingdao Intelligent&Precise Electronics Co.,Ltd.\r
+A8301C     (base 16)           Qingdao Intelligent&Precise Electronics Co.,Ltd.\r
+                               No.218 Qianwangang Road\r
+                               Qingdao  Shangdong  266510\r
+                               CN\r
+\r
+D8-F3-BC   (hex)               Liteon Technology Corporation\r
+D8F3BC     (base 16)           Liteon Technology Corporation\r
+                               4F, 90, Chien 1 Road\r
+                               New Taipei City  Taiwan  23585\r
+                               TW\r
+\r
+B8-47-7A   (hex)               Dasan Electron Co., Ltd.\r
+B8477A     (base 16)           Dasan Electron Co., Ltd.\r
+                               705 HaeAn-Ro #307, SangRok-Gu\r
+                               Ansan  KyungKi  15588\r
+                               KR\r
+\r
+7C-78-B2   (hex)               Wyze Labs Inc\r
+7C78B2     (base 16)           Wyze Labs Inc\r
+                               4030 Lake Washington Boulevard NE\r
+                               Kirkland  WA  98033\r
+                               US\r
+\r
+D8-37-3B   (hex)               Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd\r
+D8373B     (base 16)           Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd\r
+                               3/F,A5 Building Zhiyuan Community No.1001,Xueyuan Road Nanshan District\r
+                               Shenzhen  Guangdong  518055\r
+                               CN\r
+\r
+6C-2D-24   (hex)               Zhen Shi Information Technology (Shanghai) Co., Ltd.\r
+6C2D24     (base 16)           Zhen Shi Information Technology (Shanghai) Co., Ltd.\r
+                               5F, Building 3?No. 401 Caobao Road, Xuhui District, Shanghai, China\r
+                               Shanghai  Shanghai  200233\r
+                               CN\r
+\r
+B8-AE-1C   (hex)               Smart Cube., Ltd\r
+B8AE1C     (base 16)           Smart Cube., Ltd\r
+                               13F.-3, No. 78, Sec. 2, Anhe Rd., Da’an Dist., Taipei City 106, Taiwan (R.O.C.)\r
+                               Taipei    106\r
+                               TW\r
+\r
+80-03-84   (hex)               Ruckus Wireless\r
+800384     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+FC-69-8C   (hex)               ANDREAS STIHL AG & Co. KG\r
+FC698C     (base 16)           ANDREAS STIHL AG & Co. KG\r
+                               Badstraße 115\r
+                               Waiblingen    71336\r
+                               DE\r
+\r
+00-23-A7   (hex)               Redpine Signals, Inc.\r
+0023A7     (base 16)           Redpine Signals, Inc.\r
+                               Plot 87, Sagar Society \r
+                               Hyderabad  AP  500034\r
+                               IN\r
+\r
+44-CE-3A   (hex)               Jiangsu Huacun Electronic Technology Co., Ltd.\r
+44CE3A     (base 16)           Jiangsu Huacun Electronic Technology Co., Ltd.\r
+                               C4, 9th Floor, 266 New Century Avenue, Tongzhou District\r
+                               Nantong City  Jiangsu Province  226300\r
+                               CN\r
+\r
+9C-1E-A4   (hex)               Renesas Electronics (Penang) Sdn. Bhd.\r
+9C1EA4     (base 16)           Renesas Electronics (Penang) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
+\r
+4C-EF-56   (hex)               Shenzhen Sundray Technologies Company Limited\r
+4CEF56     (base 16)           Shenzhen Sundray Technologies Company Limited\r
+                               5th Floor, Block A4, Nanshan ipark,NO.1001 Xue Yuan Road, Nanshan District, Shenzhen 518055, P.R. China\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+E4-C3-2A   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+E4C32A     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+90-9A-4A   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+909A4A     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+BC-97-89   (hex)               Huawei Device Co., Ltd.\r
+BC9789     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+3C-E0-38   (hex)               Plumeria Networks, Inc.\r
+3CE038     (base 16)           Plumeria Networks, Inc.\r
+                               6701 Koll Center Parkway Suite 250\r
+                               Pleasanton  CA  94566\r
+                               US\r
+\r
+AC-12-2F   (hex)               Fantasia Trading LLC\r
+AC122F     (base 16)           Fantasia Trading LLC\r
+                               5350 Ontario Mills Pkwy, Suite 100\r
+                               Ontario  CA  91764\r
+                               US\r
+\r
+FC-45-C3   (hex)               Texas Instruments\r
+FC45C3     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+AC-6A-A3   (hex)               Shenzhen Kertong Technology Co.,Ltd\r
+AC6AA3     (base 16)           Shenzhen Kertong Technology Co.,Ltd\r
+                               405,Fuyuan Building ,District 45 Bao’an\r
+                               Shenzhen  Guangdong  518101\r
+                               CN\r
+\r
+E8-4F-4B   (hex)               Shenzhen Delos Electronic Co., Ltd\r
+E84F4B     (base 16)           Shenzhen Delos Electronic Co., Ltd\r
+                               Rm 603, Tower B, Galaxy World Building, No.1 Yabao Road,Longgang District,Shenzhen,P.R.China.\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
+\r
+B0-4A-39   (hex)               Beijing Roborock Technology Co., Ltd.\r
+B04A39     (base 16)           Beijing Roborock Technology Co., Ltd.\r
+                               Floor 6,Building C,Kangjian Baosheng Plaza,No. 8 Heiquan Road,Haidian District\r
+                               Beijing  Beijing  100085\r
+                               CN\r
+\r
+A4-F9-E4   (hex)               AirVine Scientific, Inc.\r
+A4F9E4     (base 16)           AirVine Scientific, Inc.\r
+                               1500 Wyatt Drive, Suite 9\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+F4-4F-D3   (hex)               shenzhen hemuwei technology co.,ltd\r
+F44FD3     (base 16)           shenzhen hemuwei technology co.,ltd\r
+                               220, Building C, IoT Industrial Park, Bantian Street, Longgang District\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
+\r
+68-45-71   (hex)               Huawei Device Co., Ltd.\r
+684571     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+84-93-A0   (hex)               Huawei Device Co., Ltd.\r
+8493A0     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+9C-8E-9C   (hex)               Huawei Device Co., Ltd.\r
+9C8E9C     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+40-14-AD   (hex)               Huawei Device Co., Ltd.\r
+4014AD     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+A8-74-84   (hex)               zte corporation\r
+A87484     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+E0-4B-A6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+E04BA6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+C8-B6-D3   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C8B6D3     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+FC-8D-3D   (hex)               Leapfive Tech. Ltd.\r
+FC8D3D     (base 16)           Leapfive Tech. Ltd.\r
+                               huaruizhididasha 8ceng\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+00-23-86   (hex)               IMI Hydronic Engineering international SA\r
+002386     (base 16)           IMI Hydronic Engineering international SA\r
+                               Route de Crassier 19\r
+                               Eysins    1262\r
+                               CH\r
+\r
+A0-69-74   (hex)               Honor Device Co., Ltd.\r
+A06974     (base 16)           Honor Device Co., Ltd.\r
+                               A1701, Block AB, Building 1, Tianan Yungu Phase I, Gangtou Community, Bantian Street\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+C0-33-DA   (hex)               Shenzhen JRUN Technologies CO., LTD\r
+C033DA     (base 16)           Shenzhen JRUN Technologies CO., LTD\r
+                               A Zone,9F,Huilongda Industrial Park,Shuitian Private Industrial Park,Shiyan Street,Bao,an District.\r
+                               Shenzhen  Guangdong  518101\r
+                               CN\r
+\r
+60-70-72   (hex)               SHENZHEN HONGDE SMART LINK TECHNOLOGY CO., LTD\r
+607072     (base 16)           SHENZHEN HONGDE SMART LINK TECHNOLOGY CO., LTD\r
+                               Fu Qian Road, Longhua district\r
+                               ShenZhen  GuangDong province   518000\r
+                               CN\r
+\r
+DC-B7-FC   (hex)               Alps Electric (Ireland) Ltd\r
+DCB7FC     (base 16)           Alps Electric (Ireland) Ltd\r
+                               MOUNT LEADER INDUSTRIAL ESTATE\r
+                               MILLSTREET  CO. CORK  P51 XC56\r
+                               IE\r
+\r
+AC-FA-A5   (hex)               digitron\r
+ACFAA5     (base 16)           digitron\r
+                               tehnopark A -701, 697 PanGyo-ro, Bundong \r
+                               Seongnam  GyeongGiDO  13511\r
+                               KR\r
+\r
+78-C9-5E   (hex)               Midmark RTLS \r
+78C95E     (base 16)           Midmark RTLS \r
+                               2600 Millercreek Rd\r
+                               Traverse City  MI  49684\r
+                               US\r
+\r
+20-CD-6E   (hex)               Realme Chongqing Mobile Telecommunications Corp.,Ltd.\r
+20CD6E     (base 16)           Realme Chongqing Mobile Telecommunications Corp.,Ltd.\r
+                               No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing.\r
+                               Chongqing   China  401120\r
+                               CN\r
+\r
+BC-69-CB   (hex)               Panasonic Life Solutions Networks Co., Ltd.\r
+BC69CB     (base 16)           Panasonic Life Solutions Networks Co., Ltd.\r
+                               2-12-7, Higashi-Shinbashi\r
+                               Minato-Ku  Tokyo  105-0021\r
+                               JP\r
+\r
+08-93-56   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+089356     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+00-07-89   (hex)               Allradio Co., Ltd\r
+000789     (base 16)           Allradio Co., Ltd\r
+                               76, Deokcheon-ro 34beon-gil, Manan-gu\r
+                               Anyang-si,Gyeonggi-do  Republic of Korea  430-803\r
+                               KR\r
+\r
+6C-14-6E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+6C146E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+44-E9-68   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+44E968     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
+DC-4A-9E   (hex)               IEEE Registration Authority\r
+DC4A9E     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+E0-C3-77   (hex)               Samsung Electronics Co.,Ltd\r
+E0C377     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+4C-FB-F4   (hex)               Optimal Audio Ltd\r
+4CFBF4     (base 16)           Optimal Audio Ltd\r
+                               Century Point, Halifax Rd\r
+                               High Wycombe    HP12 3SL\r
+                               GB\r
+\r
+84-60-82   (hex)               Private\r
+846082     (base 16)           Private\r
+\r
+64-03-7F   (hex)               Samsung Electronics Co.,Ltd\r
+64037F     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+B4-9D-02   (hex)               Samsung Electronics Co.,Ltd\r
+B49D02     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+80-9F-F5   (hex)               Samsung Electronics Co.,Ltd\r
+809FF5     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+64-79-24   (hex)               Huawei Device Co., Ltd.\r
+647924     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+D8-CC-98   (hex)               Huawei Device Co., Ltd.\r
+D8CC98     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+F0-4F-7C   (hex)               Amazon Technologies Inc.\r
+F04F7C     (base 16)           Amazon Technologies Inc.\r
+                               PO Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+F0-A2-25   (hex)               Amazon Technologies Inc.\r
+F0A225     (base 16)           Amazon Technologies Inc.\r
+                               PO Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+B4-0E-DE   (hex)               Intel Corporate\r
+B40EDE     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+E0-2B-E9   (hex)               Intel Corporate\r
+E02BE9     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+DC-B7-2E   (hex)               Xiaomi Communications Co Ltd\r
+DCB72E     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+B8-87-6E   (hex)               Yandex Services AG\r
+B8876E     (base 16)           Yandex Services AG\r
+                               Werftestrasse 4, \r
+                               Luzern    6005\r
+                               CH\r
+\r
+F8-6D-73   (hex)               Zengge Co., Limited\r
+F86D73     (base 16)           Zengge Co., Limited\r
+                               3/F, B Building, Second Laowei Industrial Zone, Longhua District\r
+                               Shenzhen  Guangdong  518109\r
+                               CN\r
+\r
+58-86-94   (hex)               EFM Networks\r
+588694     (base 16)           EFM Networks\r
+                               6F, Benposra II 1197-1 Bojeong Giheung Gu\r
+                               Yong In  Kyunggi do  446913\r
+                               KR\r
+\r
+AC-37-28   (hex)               Taicang T&W Electronics\r
+AC3728     (base 16)           Taicang T&W Electronics\r
+                               89# Jiang Nan RD\r
+                               Suzhou  Jiangsu  215412\r
+                               CN\r
+\r
+BC-99-30   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+BC9930     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+E8-68-E7   (hex)               Espressif Inc.\r
+E868E7     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+D0-BC-C1   (hex)               WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
+D0BCC1     (base 16)           WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
+                               Gaoxin 2 Road, Free Trade Zone,Weifang,Shandong,261205,P.R.China\r
+                               Weifang  Shandong  261205\r
+                               CN\r
+\r
+6C-E8-74   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+6CE874     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+C4-69-F0   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C469F0     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+C0-94-35   (hex)               ARRIS Group, Inc.\r
+C09435     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+18-B6-CC   (hex)               We Corporation Inc.\r
+18B6CC     (base 16)           We Corporation Inc.\r
+                               201, 33, Deokcheon-ro, Manan-gu\r
+                               Anyang-si  Gyeonggi-do  14088\r
+                               KR\r
+\r
+F8-5E-42   (hex)               Technicolor CH USA Inc.\r
+F85E42     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6 \r
+                               Lawrenceville  GA  30044\r
+                               US\r
+\r
+30-A0-23   (hex)               ROCK PATH S.R.L\r
+30A023     (base 16)           ROCK PATH S.R.L\r
+                               Via Federico Borromeo 2,  20017 Rho (MI), Italy\r
+                               Milan    20017\r
+                               IT\r
+\r
+E8-48-B8   (hex)               TP-Link Corporation Limited\r
+E848B8     (base 16)           TP-Link Corporation Limited\r
+                               Room 901,9/F.New East Ocean Centre, 9 Science Museum Road\r
+                                Tsim Sha Tsui  Kowloon  999077\r
+                               HK\r
+\r
+78-CB-2C   (hex)               Join Digital, Inc.\r
+78CB2C     (base 16)           Join Digital, Inc.\r
+                               75 E Santa Clara St., 6th Floor\r
+                               San Jose  CA  95113\r
+                               US\r
+\r
+30-9E-1D   (hex)               OHSUNG\r
+309E1D     (base 16)           OHSUNG\r
+                               335-4,SANHODAERO,GUMI,GYEONG BUK,KOREA\r
+                               GUMI  GYEONG BUK  730-030\r
+                               KR\r
+\r
+68-79-12   (hex)               IEEE Registration Authority\r
+687912     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+EC-64-88   (hex)               Honor Device Co., Ltd.\r
+EC6488     (base 16)           Honor Device Co., Ltd.\r
+                               A1701, Block AB, Building 1, Tianan Yungu Phase I, Gangtou Community, Bantian Street\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+74-D6-CB   (hex)               New H3C Technologies Co., Ltd\r
+74D6CB     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+0C-3A-FA   (hex)               New H3C Technologies Co., Ltd\r
+0C3AFA     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+28-3B-82   (hex)               D-Link International\r
+283B82     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+0C-B6-D2   (hex)               D-Link International\r
+0CB6D2     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+60-BE-C4   (hex)               Apple, Inc.\r
+60BEC4     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+F8-B1-DD   (hex)               Apple, Inc.\r
+F8B1DD     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+F8-66-5A   (hex)               Apple, Inc.\r
+F8665A     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+A8-81-7E   (hex)               Apple, Inc.\r
+A8817E     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+8C-47-6E   (hex)               IEEE Registration Authority\r
+8C476E     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+48-70-1E   (hex)               Texas Instruments\r
+48701E     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+E8-C3-20   (hex)               Austco Marketing & Service (USA) ltd.\r
+E8C320     (base 16)           Austco Marketing & Service (USA) ltd.\r
+                               9155 Sterling St Unit 100\r
+                               Irving  TX  75063\r
+                               US\r
+\r
+50-8E-49   (hex)               Xiaomi Communications Co Ltd\r
+508E49     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+AC-33-28   (hex)               Huawei Device Co., Ltd.\r
+AC3328     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+D4-76-A0   (hex)               Fortinet, Inc.\r
+D476A0     (base 16)           Fortinet, Inc.\r
+                               899 Kifer Road\r
+                               Sunnyvale    94086\r
+                               US\r
+\r
+B4-EC-02   (hex)               ALPSALPINE CO,.LTD\r
+B4EC02     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-23-06   (hex)               ALPSALPINE CO,.LTD\r
+002306     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+00-24-33   (hex)               ALPSALPINE CO,.LTD\r
+002433     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+9C-8D-7C   (hex)               ALPSALPINE CO,.LTD\r
+9C8D7C     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-16-FE   (hex)               ALPSALPINE CO,.LTD\r
+0016FE     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+00-19-C1   (hex)               ALPSALPINE CO,.LTD\r
+0019C1     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+E0-75-0A   (hex)               ALPSALPINE CO,.LTD\r
+E0750A     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               kakuda-City    981-1595\r
+                               US\r
+\r
+E0-AE-5E   (hex)               ALPSALPINE CO,.LTD\r
+E0AE5E     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-3-36 Furukawanakazato,\r
+                               Osaki  Miyagi-pref  989-6181\r
+                               JP\r
+\r
+BC-75-36   (hex)               ALPSALPINE CO,.LTD\r
+BC7536     (base 16)           ALPSALPINE CO,.LTD\r
+                               nishida  6-1 \r
+                               Kakuda-City  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+58-16-D7   (hex)               ALPSALPINE CO,.LTD\r
+5816D7     (base 16)           ALPSALPINE CO,.LTD\r
+                               nishida  6-1 \r
+                               Kakuda-City  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
 F8-D0-27   (hex)               Seiko Epson Corporation\r
 F8D027     (base 16)           Seiko Epson Corporation\r
                                2070 Kotobuki Koaka\r
@@ -101993,12 +103520,6 @@ D015A6     (base 16)         Aruba, a Hewlett Packard Enterprise Company
                                San Jose  CA  94568\r
                                US\r
 \r
-60-63-4C   (hex)               D-Link International\r
-60634C     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 20-5F-3D   (hex)               Cambridge Communication Systems Ltd\r
 205F3D     (base 16)           Cambridge Communication Systems Ltd\r
                                Victory House, Vision Park, Chivers Way, Histon\r
@@ -103169,24 +104690,12 @@ D43A2E     (base 16)                SHENZHEN MTC CO LTD
                                Ulsan    44922\r
                                KR\r
 \r
-30-C3-D9   (hex)               ALPS ELECTRIC CO., LTD.\r
-30C3D9     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 00-32-17   (hex)               Cisco Systems, Inc\r
 003217     (base 16)           Cisco Systems, Inc\r
                                80 West Tasman Drive\r
                                San Jose  CA  94568\r
                                US\r
 \r
-00-1B-FB   (hex)               ALPS ELECTRIC CO., LTD.\r
-001BFB     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
 94-E0-D6   (hex)               China Dragon Technology Limited\r
 94E0D6     (base 16)           China Dragon Technology Limited\r
                                B4 Bldg.Haoshan 1st Industry Park,\r
@@ -103433,9 +104942,6 @@ ACAE19     (base 16)          Roku, Inc
                                SHEN ZHEN  GUANG DONG  518000\r
                                CN\r
 \r
-AC-F8-5C   (hex)               Private\r
-ACF85C     (base 16)           Private\r
-\r
 3C-37-86   (hex)               NETGEAR\r
 3C3786     (base 16)           NETGEAR\r
                                350 East Plumeria Drive\r
@@ -103628,12 +105134,6 @@ F063F9     (base 16)         HUAWEI TECHNOLOGIES CO.,LTD
                                Roseville  CA  95747\r
                                US\r
 \r
-00-AD-24   (hex)               D-Link International\r
-00AD24     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 54-06-8B   (hex)               Ningbo Deli Kebei Technology Co.LTD\r
 54068B     (base 16)           Ningbo Deli Kebei Technology Co.LTD\r
                                zone 2nd , 301#, Road Xuxiake, Ninghai yuelong district\r
@@ -104936,12 +106436,6 @@ DC0265     (base 16)         Meditech Kft
                                Budapest    1191\r
                                HU\r
 \r
-18-0F-76   (hex)               D-Link International\r
-180F76     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 14-A7-2B   (hex)               currentoptronics Pvt.Ltd\r
 14A72B     (base 16)           currentoptronics Pvt.Ltd\r
                                CRT Building, Jupitor Jn , Near Time kids Koothattukulam - Piravom Rd\r
@@ -123719,12 +125213,6 @@ A07332     (base 16)         Cashmaster International Limited
                                Orlando  FL  32837\r
                                US\r
 \r
-00-16-3B   (hex)               VertexRSI/General Dynamics\r
-00163B     (base 16)           VertexRSI/General Dynamics\r
-                               2120 Old Gatesburg Rd.\r
-                               State college  PA  16803\r
-                               US\r
-\r
 00-16-37   (hex)               CITEL SpA\r
 001637     (base 16)           CITEL SpA\r
                                Via L. G. Columella, 36\r
@@ -126563,12 +128051,6 @@ A07332     (base 16)         Cashmaster International Limited
                                Zilina    01124\r
                                SK\r
 \r
-00-0B-4E   (hex)               VertexRSI, General Dynamics SatCOM Technologies, Inc.\r
-000B4E     (base 16)           VertexRSI, General Dynamics SatCOM Technologies, Inc.\r
-                               3750 W. Loop 281\r
-                               Longview  TX  75604\r
-                               US\r
-\r
 00-0B-4D   (hex)               Emuzed\r
 000B4D     (base 16)           Emuzed\r
                                46750 Lakeview Boulevard\r
@@ -128774,12 +130256,6 @@ A06A00     (base 16)         Verilink Corporation
                                TAIWAN  TAIWAN  R.O.C.\r
                                TW\r
 \r
-00-03-34   (hex)               Newport Electronics\r
-000334     (base 16)           Newport Electronics\r
-                               2229 So. Yale St.\r
-                               Santa Ana  CA  92704\r
-                               US\r
-\r
 00-03-3A   (hex)               Silicon Wave, Inc.\r
 00033A     (base 16)           Silicon Wave, Inc.\r
                                6256 Greenwich Drive\r
@@ -133262,12 +134738,6 @@ BCA511     (base 16)         NETGEAR
                                Hattingen  NRW  45527\r
                                DE\r
 \r
-C4-E9-0A   (hex)               D-Link International\r
-C4E90A     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 C4-44-7D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
 C4447D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
                                No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
@@ -133445,12 +134915,6 @@ C0B5CD     (base 16)         Huawei Device Co., Ltd.
                                Foshan  Guangdong  528311\r
                                CN\r
 \r
-84-EA-97   (hex)               Shenzhen iComm Semiconductor Co., Ltd.\r
-84EA97     (base 16)           Shenzhen iComm Semiconductor Co., Ltd.\r
-                               Room 501A,Block B,Digital Building,Garden City,No.1079 Nanhai Road,Nanshan District\r
-                               Shenzhen    518067\r
-                               CN\r
-\r
 5C-3A-3D   (hex)               zte corporation\r
 5C3A3D     (base 16)           zte corporation\r
                                12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
@@ -133529,12 +134993,6 @@ B0735D     (base 16)         Huawei Device Co., Ltd.
                                Dongguan  Guangdong  523808\r
                                CN\r
 \r
-F0-B4-D2   (hex)               D-Link International\r
-F0B4D2     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 5C-3A-45   (hex)               CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
 5C3A45     (base 16)           CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
                                Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
@@ -135530,18 +136988,612 @@ EC3EB3     (base 16)               Zyxel Communications Corporation
                                Seoul    05836\r
                                KR\r
 \r
+FC-44-9F   (hex)               zte corporation\r
+FC449F     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+20-4E-F6   (hex)               AzureWave Technology Inc.\r
+204EF6     (base 16)           AzureWave Technology Inc.\r
+                               8F., No. 94, Baozhong Rd.\r
+                               New Taipei City  Taiwan  231\r
+                               TW\r
+\r
 44-35-83   (hex)               Apple, Inc.\r
 443583     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
                                Cupertino  CA  95014\r
                                US\r
 \r
-FC-44-9F   (hex)               zte corporation\r
-FC449F     (base 16)           zte corporation\r
+38-CA-73   (hex)               Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
+38CA73     (base 16)           Shenzhen MiaoMing  Intelligent Technology Co.,Ltd\r
+                               Chudong science and technology park, 111 shaxin road, tangxia town,\r
+                               dongguan city  guangdong province  523710\r
+                               CN\r
+\r
+6C-0D-C4   (hex)               Beijing Xiaomi Electronics Co., Ltd.\r
+6C0DC4     (base 16)           Beijing Xiaomi Electronics Co., Ltd.\r
+                               Building C, QingHe ShunShiJiaYe Technology Park, #66 ZhuFang Rd, HaiDian District\r
+                               Beijing  Beijing  10085\r
+                               CN\r
+\r
+C4-40-F6   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+C440F6     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+A4-7D-9F   (hex)               Shenzhen iComm Semiconductor CO.,LTD\r
+A47D9F     (base 16)           Shenzhen iComm Semiconductor CO.,LTD\r
+                               Room 504A,Block B,Digital Building,Gargen City,No.1079,Nanhai Road,Nanshan District,Shenzhen.\r
+                               Shenzhen    518067\r
+                               CN\r
+\r
+84-EA-97   (hex)               Shenzhen iComm Semiconductor CO.,LTD\r
+84EA97     (base 16)           Shenzhen iComm Semiconductor CO.,LTD\r
+                               Room 501A,Block B,Digital Building,Garden City,No.1079 Nanhai Road,Nanshan District\r
+                               Shenzhen    518067\r
+                               CN\r
+\r
+00-55-B1   (hex)               Shanghai Baud Data Communication Co.,Ltd.\r
+0055B1     (base 16)           Shanghai Baud Data Communication Co.,Ltd.\r
+                               NO.123 JULI RD\r
+                               PUDONG ZHANGJIANG HIGH-TECH PARK  SHANGHAI  201203\r
+                               CN\r
+\r
+74-90-1F   (hex)               Ragile Networks Inc.\r
+74901F     (base 16)           Ragile Networks Inc.\r
+                               35649 Embassy common Fremont ca 94536\r
+                               Fremont  CA  94536\r
+                               US\r
+\r
+C0-25-2F   (hex)               SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.\r
+C0252F     (base 16)           SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.\r
+                               3/F, Building R1-B, High-Tech Industrial Park, Nanshan District\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+54-9F-C6   (hex)               Cisco Systems, Inc\r
+549FC6     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+F0-1D-2D   (hex)               Cisco Systems, Inc\r
+F01D2D     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+68-3E-26   (hex)               Intel Corporate\r
+683E26     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+8C-55-4A   (hex)               Intel Corporate\r
+8C554A     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+40-1C-83   (hex)               Intel Corporate\r
+401C83     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+44-3B-32   (hex)               Intelbras\r
+443B32     (base 16)           Intelbras\r
+                               BR 101, km 210, S/N°\r
+                               São José  Santa Catarina  88104800\r
+                               BR\r
+\r
+F8-3B-1D   (hex)               Technicolor CH USA Inc.\r
+F83B1D     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6 \r
+                               Lawrenceville  GA  30044\r
+                               US\r
+\r
+D4-1B-81   (hex)               CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+D41B81     (base 16)           CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
+                               Chongqing  Chongqing  401332\r
+                               CN\r
+\r
+F4-0B-9F   (hex)               CIG SHANGHAI CO LTD\r
+F40B9F     (base 16)           CIG SHANGHAI CO LTD\r
+                               5th Floor, Building 8 No 2388 Chenhang Road\r
+                               SHANGHAI    201114\r
+                               CN\r
+\r
+78-45-B3   (hex)               Huawei Device Co., Ltd.\r
+7845B3     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+20-DC-FD   (hex)               Huawei Device Co., Ltd.\r
+20DCFD     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+FC-65-B3   (hex)               Huawei Device Co., Ltd.\r
+FC65B3     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+10-9D-7A   (hex)               Huawei Device Co., Ltd.\r
+109D7A     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+DC-63-73   (hex)               OBARA KOREA\r
+DC6373     (base 16)           OBARA KOREA\r
+                               97-23, Barangongdan-ro 4-gil\r
+                               Hwaseong-si  Gyeonggi-do  18623\r
+                               KR\r
+\r
+D4-7E-E4   (hex)               China Mobile IOT Company Limited\r
+D47EE4     (base 16)           China Mobile IOT Company Limited\r
+                               NO.8 Yu Ma Road, NanAn Area\r
+                               Chongqing  Chongqing  401336\r
+                               CN\r
+\r
+88-89-2F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+88892F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+28-E5-B0   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+28E5B0     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+4C-02-20   (hex)               Xiaomi Communications Co Ltd\r
+4C0220     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+1C-A8-52   (hex)               SENSAIO PTE LTD\r
+1CA852     (base 16)           SENSAIO PTE LTD\r
+                               160 Robinson Road #14-04\r
+                               SINGAPORE  SINGAPORE  068914\r
+                               SG\r
+\r
+78-7D-F3   (hex)               Sterlite Technologies Limited\r
+787DF3     (base 16)           Sterlite Technologies Limited\r
+                               IFFCO Tower, 3rd Floor, Plot No.3, Sector 29,CH Baktawar Singh Rd, Institutional Area,\r
+                               Gurugram  Haryana  122002\r
+                               IN\r
+\r
+C0-94-AD   (hex)               zte corporation\r
+C094AD     (base 16)           zte corporation\r
                                12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
                                shenzhen  guangdong  518057\r
                                CN\r
 \r
+D0-21-AC   (hex)               Yo Labs LLC\r
+D021AC     (base 16)           Yo Labs LLC\r
+                               3460 Hillview Ave.\r
+                               Palo Alto  CA  94304\r
+                               US\r
+\r
+34-2B-70   (hex)               Arris\r
+342B70     (base 16)           Arris\r
+                               2500 Walsh Ave.\r
+                               Santa Clara  CA  95014\r
+                               US\r
+\r
+1C-90-BE   (hex)               Ericsson AB\r
+1C90BE     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
+\r
+00-16-3B   (hex)               Communications & Power Industries\r
+00163B     (base 16)           Communications & Power Industries\r
+                               Suite , 60 Decibel Road\r
+                               State College  PA  16801\r
+                               US\r
+\r
+9C-B2-E8   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+9CB2E8     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+74-73-1D   (hex)               ifm electronic gmbh\r
+74731D     (base 16)           ifm electronic gmbh\r
+                               ifm-Straße 1\r
+                               Tettnang  BW  88069\r
+                               DE\r
+\r
+00-0B-4E   (hex)               Communications & Power Industries\r
+000B4E     (base 16)           Communications & Power Industries\r
+                               1000 Klein Road\r
+                               Plano  TX  75074\r
+                               US\r
+\r
+00-03-34   (hex)               Omega Engineering Inc.\r
+000334     (base 16)           Omega Engineering Inc.\r
+                               800 Connecticut Ave. Suite 5N01,\r
+                               Norwalk  CT  06854\r
+                               US\r
+\r
+5C-61-99   (hex)               CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.\r
+5C6199     (base 16)           CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.\r
+                               B22 Building,NO.51 Tongle Road, Shajing Town, Jiangnan District, Nanning, Guangxi Province, China\r
+                               Nanning  Guangxi  530007\r
+                               CN\r
+\r
+E8-DB-84   (hex)               Espressif Inc.\r
+E8DB84     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+D0-55-09   (hex)               Nintendo Co.,Ltd\r
+D05509     (base 16)           Nintendo Co.,Ltd\r
+                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
+                               KYOTO  KYOTO  601-8501\r
+                               JP\r
+\r
+A0-77-51   (hex)               ASMedia Technology Inc.\r
+A07751     (base 16)           ASMedia Technology Inc.\r
+                               6F, No.115, Minquan Rd.,\r
+                               New Taipei City    23141\r
+                               TW\r
+\r
+30-56-84   (hex)               SHENZHEN YUNJI INTELLIGENT TECHNOLOGY CO.,LTD\r
+305684     (base 16)           SHENZHEN YUNJI INTELLIGENT TECHNOLOGY CO.,LTD\r
+                               A-SIDE A2 BUILDING 2/F ENET NEW INDUSTRIAL PARK,NO.20 DAFU INDUSTRIAL ZONE, AOBEI COMMUNITY, GUANLAN, LONGHUA NEW DISTRICT\r
+                               SHENZHEN  GUANGDONG  518000\r
+                               CN\r
+\r
+14-56-3A   (hex)               Huawei Device Co., Ltd.\r
+14563A     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+70-90-B7   (hex)               Huawei Device Co., Ltd.\r
+7090B7     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+38-FC-98   (hex)               Intel Corporate\r
+38FC98     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+24-94-94   (hex)               Hong Kong Bouffalo Lab Limited\r
+249494     (base 16)           Hong Kong Bouffalo Lab Limited\r
+                               RM 1903, 19/F Lee Garden One 33 Hysan Avenue, Causeway Bay\r
+                               HongKong    999077\r
+                               HK\r
+\r
+30-BE-3B   (hex)               Mitsubishi Electric Corporation\r
+30BE3B     (base 16)           Mitsubishi Electric Corporation\r
+                               2-7-3 Marunouchi, Chiyoda-ku\r
+                               Tokyo    100-8310\r
+                               JP\r
+\r
+0C-B7-89   (hex)               Honor Device Co., Ltd.\r
+0CB789     (base 16)           Honor Device Co., Ltd.\r
+                               A1701, Block AB, Building 1, Tianan Yungu Phase I, Gangtou Community, Bantian Street\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+78-91-E9   (hex)               Raisecom Technology CO.,LTD\r
+7891E9     (base 16)           Raisecom Technology CO.,LTD\r
+                               No. 11, East Area, No. 10 Block, East Xibeiwang Road\r
+                               Beijing    100094\r
+                               CN\r
+\r
+8C-34-01   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+8C3401     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+60-DB-98   (hex)               Calix Inc.\r
+60DB98     (base 16)           Calix Inc.\r
+                               2777 Orchard Pkwy\r
+                               San Jose  CA  95131\r
+                               US\r
+\r
+68-72-C3   (hex)               Samsung Electronics Co.,Ltd\r
+6872C3     (base 16)           Samsung Electronics Co.,Ltd\r
+                               129, Samsung-ro, Youngtongl-Gu\r
+                               Suwon  Gyeonggi-Do  16677\r
+                               KR\r
+\r
+70-B1-3D   (hex)               Samsung Electronics Co.,Ltd\r
+70B13D     (base 16)           Samsung Electronics Co.,Ltd\r
+                               129, Samsung-ro, Youngtongl-Gu\r
+                               Suwon  Gyeonggi-Do  16677\r
+                               KR\r
+\r
+FC-7F-F1   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+FC7FF1     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+3C-A3-7E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+3CA37E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+F8-E4-3B   (hex)               ASIX Electronics Corporation\r
+F8E43B     (base 16)           ASIX Electronics Corporation\r
+                               4F, No. 8, Hsin Ann Road, Hsinchu Science Park\r
+                               Hsinchu    30078\r
+                               TW\r
+\r
+F8-5E-A0   (hex)               Intel Corporate\r
+F85EA0     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+50-2F-9B   (hex)               Intel Corporate\r
+502F9B     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3 \r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+48-EF-61   (hex)               Huawei Device Co., Ltd.\r
+48EF61     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+78-F0-9B   (hex)               Huawei Device Co., Ltd.\r
+78F09B     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+00-E9-3A   (hex)               AzureWave Technology Inc.\r
+00E93A     (base 16)           AzureWave Technology Inc.\r
+                               8F., No. 94, Baozhong Rd.\r
+                               New Taipei City  Taiwan  231\r
+                               TW\r
+\r
+00-C5-2C   (hex)               Juniper Networks\r
+00C52C     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+00-34-A1   (hex)               RF-LAMBDA USA INC.\r
+0034A1     (base 16)           RF-LAMBDA USA INC.\r
+                               9115 Brown Deer Road | San Diego\r
+                               CA    92121\r
+                               US\r
+\r
+60-35-73   (hex)               Earda Technologies co Ltd\r
+603573     (base 16)           Earda Technologies co Ltd\r
+                               Block A,Lianfeng Creative Park, #2 Jisheng Rd., Nansha District\r
+                               Guangzhou  Guangdong  511455\r
+                               CN\r
+\r
+A4-97-33   (hex)               ASKEY COMPUTER CORP\r
+A49733     (base 16)           ASKEY COMPUTER CORP\r
+                               10F,No.119,JIANKANG RD,ZHONGHE DIST\r
+                               NEW TAIPEI  TAIWAN  23585\r
+                               TW\r
+\r
+5C-FB-3A   (hex)               CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+5CFB3A     (base 16)           CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
+                               Chongqing  Chongqing  401332\r
+                               CN\r
+\r
+18-0F-76   (hex)               D-Link International\r
+180F76     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+00-AD-24   (hex)               D-Link International\r
+00AD24     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+60-63-4C   (hex)               D-Link International\r
+60634C     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+C4-E9-0A   (hex)               D-Link International\r
+C4E90A     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+F0-B4-D2   (hex)               D-Link International\r
+F0B4D2     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+E0-1C-FC   (hex)               D-Link International\r
+E01CFC     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+F0-2F-74   (hex)               ASUSTek COMPUTER INC.\r
+F02F74     (base 16)           ASUSTek COMPUTER INC.\r
+                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
+                               Taipei  Taiwan  112\r
+                               TW\r
+\r
+00-6E-02   (hex)               Xovis AG\r
+006E02     (base 16)           Xovis AG\r
+                               Industriestrasse 1\r
+                               Zollikofen  Bern  3052\r
+                               CH\r
+\r
+AC-F8-5C   (hex)               Chengdu Higon Integrated Circuit Design Co,. Ltd.\r
+ACF85C     (base 16)           Chengdu Higon Integrated Circuit Design Co,. Ltd.\r
+                               Suite22-31, 11Floor, Block E5,Tianfu Software Park, Chengdu Gaoxin District\r
+                               Chengdu  Sichuan  610041\r
+                               CN\r
+\r
+18-11-71   (hex)               Guangzhou Doctorpai Education & Technology Co.,Ltd\r
+181171     (base 16)           Guangzhou Doctorpai Education & Technology Co.,Ltd\r
+                               Floor 5, Building C1, Greenland Central Plaza\r
+                               Huangpu District, Guangzhou  Guangdong Province  510700\r
+                               CN\r
+\r
+E0-6D-17   (hex)               Apple, Inc.\r
+E06D17     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+F0-B3-EC   (hex)               Apple, Inc.\r
+F0B3EC     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+F4-65-A6   (hex)               Apple, Inc.\r
+F465A6     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+78-98-E8   (hex)               D-Link International\r
+7898E8     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+44-F2-1B   (hex)               Apple, Inc.\r
+44F21B     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+74-65-0C   (hex)               Apple, Inc.\r
+74650C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+FC-D4-36   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+FCD436     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+0C-EC-8D   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+0CEC8D     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+18-4F-5D   (hex)               JRC Mobility Inc.\r
+184F5D     (base 16)           JRC Mobility Inc.\r
+                               NAKANO CENTRAL PARK EAST 10-1, Nakano 4-chome\r
+                               Nakano-ku  Tokyo  164-8570\r
+                               JP\r
+\r
+10-3F-44   (hex)               Xiaomi Communications Co Ltd\r
+103F44     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+08-CB-E5   (hex)               R3 - Reliable Realtime Radio Communications GmbH\r
+08CBE5     (base 16)           R3 - Reliable Realtime Radio Communications GmbH\r
+                               Bismarckstrasse 10-12\r
+                               Berlin  Berlin  10625\r
+                               DE\r
+\r
+F0-23-AE   (hex)               AMPAK Technology,Inc.\r
+F023AE     (base 16)           AMPAK Technology,Inc.\r
+                               3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou,\r
+                               Hsinchu  Hsinchu,Taiwan R.O.C.  30352\r
+                               TW\r
+\r
+E0-77-26   (hex)               Huawei Device Co., Ltd.\r
+E07726     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+94-A6-7E   (hex)               NETGEAR\r
+94A67E     (base 16)           NETGEAR\r
+                               350 East Plumeria Drive\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+A8-9A-D7   (hex)               Nokia\r
+A89AD7     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+48-25-67   (hex)               Poly\r
+482567     (base 16)           Poly\r
+                               6001 America Center Drive\r
+                               San Jose  CA  95002\r
+                               US\r
+\r
+F8-7A-41   (hex)               Cisco Systems, Inc\r
+F87A41     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+84-F1-47   (hex)               Cisco Systems, Inc\r
+84F147     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+24-9F-89   (hex)               Texas Instruments\r
+249F89     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+24-76-25   (hex)               Texas Instruments\r
+247625     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+30-C3-D9   (hex)               ALPSALPINE CO,.LTD\r
+30C3D9     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-1B-FB   (hex)               ALPSALPINE CO,.LTD\r
+001BFB     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
 7C-8A-E1   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
 7C8AE1     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
                                NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE \r
@@ -136391,12 +138443,6 @@ A8A159     (base 16)         ASRock Incorporation
                                Taipei    112\r
                                TW\r
 \r
-EC-AD-E0   (hex)               D-Link International\r
-ECADE0     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 78-DA-07   (hex)               Zhejiang Tmall Technology Co., Ltd.\r
 78DA07     (base 16)           Zhejiang Tmall Technology Co., Ltd.\r
                                Ali Center,No.3331 Keyuan South RD (Shenzhen bay), Nanshan District, \r
@@ -136955,48 +139001,12 @@ F085C1     (base 16)                SHENZHEN RF-LINK TECHNOLOGY CO.,LTD.
                                Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-60-38-0E   (hex)               ALPS ELECTRIC CO., LTD.\r
-60380E     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi\r
-                               Soma-city  Fukushima  976-8501\r
-                               JP\r
-\r
-FC-62-B9   (hex)               ALPS ELECTRIC CO., LTD.\r
-FC62B9     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               kakuda-city  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
-00-02-C7   (hex)               ALPS ELECTRIC CO., LTD.\r
-0002C7     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi, Sama-City,\r
-                               Sama    00000\r
-                               JP\r
-\r
-00-1E-3D   (hex)               ALPS ELECTRIC CO., LTD.\r
-001E3D     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
-\r
-28-A1-83   (hex)               ALPS ELECTRIC CO., LTD.\r
-28A183     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 4C-DD-7D   (hex)               LHP Telematics LLC\r
 4CDD7D     (base 16)           LHP Telematics LLC\r
                                17406 Tiller Ct. STE 100\r
                                westfield  IN  46074\r
                                US\r
 \r
-48-F0-7B   (hex)               ALPS ELECTRIC CO., LTD.\r
-48F07B     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
-\r
 B8-BC-5B   (hex)               Samsung Electronics Co.,Ltd\r
 B8BC5B     (base 16)           Samsung Electronics Co.,Ltd\r
                                129, Samsung-ro, Youngtongl-Gu\r
@@ -137033,12 +139043,6 @@ A4F465     (base 16)         ITEL MOBILE LIMITED
                                Piscataway  NJ  08554\r
                                US\r
 \r
-F4-8C-EB   (hex)               D-Link International\r
-F48CEB     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 74-3A-65   (hex)               NEC Corporation\r
 743A65     (base 16)           NEC Corporation\r
                                7-1, Shiba 5-chome, Minato-ku\r
@@ -137870,12 +139874,6 @@ DC3979     (base 16)         Cisco Systems, Inc
                                Mountain View  CA  94041\r
                                US\r
 \r
-58-D5-6E   (hex)               D-Link International\r
-58D56E     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 0C-53-31   (hex)               ETH Zurich\r
 0C5331     (base 16)           ETH Zurich\r
                                Dept. Computer Science, Universitätstr. 6\r
@@ -148880,12 +150878,6 @@ CCA0E5     (base 16)         DZG Metering GmbH
                                Oranienburg  Brandenburg  16515\r
                                DE\r
 \r
-60-81-2B   (hex)               Custom Control Concepts\r
-60812B     (base 16)           Custom Control Concepts\r
-                               6020 S 190th ST\r
-                               Kent  Washington  98032\r
-                               US\r
-\r
 1C-1C-FD   (hex)               Dalian Hi-Think Computer Technology, Corp\r
 1C1CFD     (base 16)           Dalian Hi-Think Computer Technology, Corp\r
                                Hi-Think Software Building,No.6 Hi-Tech Street, Qixianling Industrial Base, Hi-Tech Zone, Dalian, China\r
@@ -156797,12 +158789,6 @@ EC6C9F     (base 16)         Chengdu Volans Technology CO.,LTD
                                Mountain View  CA  94043\r
                                US\r
 \r
-00-1A-65   (hex)               Seluxit\r
-001A65     (base 16)           Seluxit\r
-                               Nyhavnsgade 9, 2.sal\r
-                               Aalborg  Nord Jylland  9000\r
-                               DK\r
-\r
 00-1A-54   (hex)               Hip Shing Electronics Ltd.\r
 001A54     (base 16)           Hip Shing Electronics Ltd.\r
                                Unit 1/2/3, 20/F, New Treasure Center\r
@@ -158312,12 +160298,6 @@ EC6C9F     (base 16)         Chengdu Volans Technology CO.,LTD
                                Barneveld  Gelderland  3772 MT\r
                                NL\r
 \r
-00-14-5A   (hex)               Neratec Solutions AG\r
-00145A     (base 16)           Neratec Solutions AG\r
-                               Rosswiesstrasse 29\r
-                               CH-8608  Bubikon  ZH\r
-                               CH\r
-\r
 00-14-5B   (hex)               SeekerNet Inc.\r
 00145B     (base 16)           SeekerNet Inc.\r
                                300 Satellite Blvd.\r
@@ -164504,12 +166484,6 @@ EC6C9F     (base 16)         Chengdu Volans Technology CO.,LTD
                                SEOCHO-KU   SEOUL  \r
                                KR\r
 \r
-00-90-D2   (hex)               ARTEL VIDEO SYSTEMS\r
-0090D2     (base 16)           ARTEL VIDEO SYSTEMS\r
-                               237 CEDAR HILL ST.\r
-                               MARLBORO  MA  01752\r
-                               US\r
-\r
 00-01-FE   (hex)               DIGITAL EQUIPMENT CORPORATION\r
 0001FE     (base 16)           DIGITAL EQUIPMENT CORPORATION\r
                                301 ROCKRIMMON BLVD, SOUTH\r
@@ -168839,12 +170813,6 @@ DC91BF     (base 16)         Amazon Technologies Inc.
                                Reno  NV  89507\r
                                US\r
 \r
-98-C9-7C   (hex)               Shenzhen iComm Semiconductor CO,LTD\r
-98C97C     (base 16)           Shenzhen iComm Semiconductor CO,LTD\r
-                               Room 504A,Block B,Digital Building,Garden City,No.1079 Nanhai Road,Nanshan District,Shenzhen\r
-                               shenzhen  Guangdong  518067\r
-                               CN\r
-\r
 E0-92-A7   (hex)               Feitian Technologies Co., Ltd\r
 E092A7     (base 16)           Feitian Technologies Co., Ltd\r
                                Floor 17, Tower B, Huizhi Mansion, No.9 Xueqing Rd, Haidian District\r
@@ -168923,12 +170891,6 @@ BCE92F     (base 16)         HP Inc.
                                Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-34-0A-33   (hex)               D-Link International\r
-340A33     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
-\r
 84-D8-1B   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
 84D81B     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
                                Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
@@ -169451,8 +171413,572 @@ A0FBC5     (base 16)                Apple, Inc.
                                Cupertino  CA  95014\r
                                US\r
 \r
+EC-C3-02   (hex)               HUMAX Co., Ltd.\r
+ECC302     (base 16)           HUMAX Co., Ltd.\r
+                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
+                               Seongnam-si  Gyeonggi-do  463-875\r
+                               KR\r
+\r
+98-C9-7C   (hex)               Shenzhen iComm Semiconductor CO.,LTD\r
+98C97C     (base 16)           Shenzhen iComm Semiconductor CO.,LTD\r
+                               Room 504A,Block B,Digital Building,Garden City,No.1079 Nanhai Road,Nanshan District,Shenzhen\r
+                               shenzhen  Guangdong  518067\r
+                               CN\r
+\r
+00-C3-43   (hex)               E-T-A Circuit Breakers Ltd\r
+00C343     (base 16)           E-T-A Circuit Breakers Ltd\r
+                               6 Telford Close\r
+                               Aylesbury  Buckinghamshire  HP198DG\r
+                               GB\r
+\r
 58-20-8A   (hex)               IEEE Registration Authority\r
 58208A     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
                                Piscataway  NJ  08554\r
                                US\r
+\r
+00-90-D2   (hex)               Artel Video Systems\r
+0090D2     (base 16)           Artel Video Systems\r
+                               5B Lyberty Way\r
+                               Westford  MA  01886\r
+                               US\r
+\r
+6C-1E-D7   (hex)               vivo Mobile Communication Co., Ltd.\r
+6C1ED7     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
+                               CN\r
+\r
+F0-AA-0B   (hex)               Arra Networks/ Spectramesh\r
+F0AA0B     (base 16)           Arra Networks/ Spectramesh\r
+                               9201 Ward Pkwy #101\r
+                               Kansas City  MO  64114\r
+                               US\r
+\r
+94-56-41   (hex)               Palo Alto Networks\r
+945641     (base 16)           Palo Alto Networks\r
+                               3000 Tannery Way\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+80-F5-B5   (hex)               Texas Instruments\r
+80F5B5     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+1C-30-08   (hex)               Hui Zhou Gaoshengda Technology Co.,LTD\r
+1C3008     (base 16)           Hui Zhou Gaoshengda Technology Co.,LTD\r
+                               No.75,Zhongkai High-Tech Development District,Huizhou\r
+                               Hui Zhou  Guangdong  516006\r
+                               CN\r
+\r
+98-06-3A   (hex)               Home Control Singapore Pte Ltd\r
+98063A     (base 16)           Home Control Singapore Pte Ltd\r
+                               151 Lorong Chuan\r
+                               Singapore    556741\r
+                               SG\r
+\r
+B4-BA-12   (hex)               China Mobile (Hangzhou) Information Technology Co.,Ltd.\r
+B4BA12     (base 16)           China Mobile (Hangzhou) Information Technology Co.,Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  311100\r
+                               CN\r
+\r
+5C-F9-FD   (hex)               Taicang T&W Electronics\r
+5CF9FD     (base 16)           Taicang T&W Electronics\r
+                               89# Jiang Nan RD\r
+                               Suzhou  Jiangsu  215412\r
+                               CN\r
+\r
+38-98-E9   (hex)               Huawei Device Co., Ltd.\r
+3898E9     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+48-A5-16   (hex)               Huawei Device Co., Ltd.\r
+48A516     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+18-36-72   (hex)               Shaoxing ShunChuang Technology CO.,LTD\r
+183672     (base 16)           Shaoxing ShunChuang Technology CO.,LTD\r
+                               N.O.398 west tongjiang load shangyu\r
+                               Shaoxing  Zhejiang  312300\r
+                               CN\r
+\r
+28-DE-65   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+28DE65     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+B0-A6-51   (hex)               Cisco Systems, Inc\r
+B0A651     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+D4-91-0F   (hex)               Amazon Technologies Inc.\r
+D4910F     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+B8-5F-B0   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+B85FB0     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+C4-FB-AA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C4FBAA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+AC-DC-CA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+ACDCCA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+64-A2-00   (hex)               Xiaomi Communications Co Ltd\r
+64A200     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+C0-78-31   (hex)               Huawei Device Co., Ltd.\r
+C07831     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+84-CC-63   (hex)               Huawei Device Co., Ltd.\r
+84CC63     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+E0-E0-C2   (hex)               China Mobile Group Device Co.,Ltd.\r
+E0E0C2     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street,Xicheng District\r
+                               Beijing    100053\r
+                               CN\r
+\r
+F0-64-26   (hex)               Extreme Networks, Inc.\r
+F06426     (base 16)           Extreme Networks, Inc.\r
+                               6480 Via Del Oro\r
+                               San Jose  CA  95119\r
+                               US\r
+\r
+70-3A-2D   (hex)               Shenzhen V-Link Technology CO., LTD.\r
+703A2D     (base 16)           Shenzhen V-Link Technology CO., LTD.\r
+                               Room 1803, BaiRuiDa Building, Bantian Sub-district, LongGang District\r
+                               Shenzhen  GuangDong  518000\r
+                               CN\r
+\r
+1C-45-C2   (hex)               Huizhou City Sunsin lntelligent Technology Co.,Ltd\r
+1C45C2     (base 16)           Huizhou City Sunsin lntelligent Technology Co.,Ltd\r
+                               Outside No.6 community, Zhongkai high tech Zone, Huizhou\r
+                               Huizhou    516000\r
+                               CN\r
+\r
+7C-4E-09   (hex)               Shenzhen Skyworth Wireless Technology Co.,Ltd\r
+7C4E09     (base 16)           Shenzhen Skyworth Wireless Technology Co.,Ltd\r
+                               Unit 3A01,Block A Skyworth Building,Gaoxin Ave.I.S.,Nanshan District\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+EC-7E-91   (hex)               ITEL MOBILE LIMITED\r
+EC7E91     (base 16)           ITEL MOBILE LIMITED\r
+                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
+                               Hong Kong  KOWLOON  999077\r
+                               HK\r
+\r
+FC-96-43   (hex)               Juniper Networks\r
+FC9643     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+A8-B0-88   (hex)               eero inc.\r
+A8B088     (base 16)           eero inc.\r
+                               660 3rd Street\r
+                               San Francisco  CA  94107\r
+                               US\r
+\r
+00-1A-65   (hex)               Seluxit\r
+001A65     (base 16)           Seluxit\r
+                               Sofiendalsvej 74\r
+                               Aalborg  SV  9200\r
+                               DK\r
+\r
+28-0F-C5   (hex)               Beijing Leadsec Technology Co., Ltd.\r
+280FC5     (base 16)           Beijing Leadsec Technology Co., Ltd.\r
+                               Venus Plaza No.21Zhongguancun Software Park,No.8 Dongbeiwang Xilu, Haidian District\r
+                               Beijing  Beijing  100193\r
+                               CN\r
+\r
+1C-EC-72   (hex)               Allradio Co., Ltd\r
+1CEC72     (base 16)           Allradio Co., Ltd\r
+                               76, Deokcheon-ro 34beon-gil, Manan-gu\r
+                               Anyang-si,Gyeonggi-do  Republic of Korea  430-803\r
+                               KR\r
+\r
+E0-E1-A9   (hex)               Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
+E0E1A9     (base 16)           Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
+                               Room 607-610, Block B, TAOJINDI Electronic Business Incubation Base\r
+                               Tenglong Road, Longhua District,   Shenzhen Guangdong  518000\r
+                               CN\r
+\r
+6C-14-14   (hex)               BUJEON ELECTRONICS Co,.Ltd\r
+6C1414     (base 16)           BUJEON ELECTRONICS Co,.Ltd\r
+                               59, Seonjinan-gil, Sangnok-gu\r
+                               Ansan-si  Gyeonggi-do  15633\r
+                               KR\r
+\r
+C4-3C-EA   (hex)               BUFFALO.INC\r
+C43CEA     (base 16)           BUFFALO.INC\r
+                               AKAMONDORI Bld.,30-20,Ohsu 3-chome,Naka-ku\r
+                               Nagoya  Aichi Pref.  460-8315\r
+                               JP\r
+\r
+B0-EC-DD   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+B0ECDD     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+AC-67-84   (hex)               Google, Inc.\r
+AC6784     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+90-DE-80   (hex)               Shenzhen Century Xinyang Technology Co., Ltd\r
+90DE80     (base 16)           Shenzhen Century Xinyang Technology Co., Ltd\r
+                               3F, North Building, Bantian High-tech industrial Zone, No. 2 of Bell Road\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+E4-DC-43   (hex)               Huawei Device Co., Ltd.\r
+E4DC43     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+24-30-F8   (hex)               Huawei Device Co., Ltd.\r
+2430F8     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+9C-5F-B0   (hex)               Samsung Electronics Co.,Ltd\r
+9C5FB0     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+E8-7F-6B   (hex)               Samsung Electronics Co.,Ltd\r
+E87F6B     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+FC-B6-9D   (hex)               Zhejiang Dahua Technology Co., Ltd.\r
+FCB69D     (base 16)           Zhejiang Dahua Technology Co., Ltd.\r
+                               No.1199,Waterfront Road \r
+                               Hangzhou  Zhejiang  310053\r
+                               CN\r
+\r
+18-5B-B3   (hex)               Samsung Electronics Co.,Ltd\r
+185BB3     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+94-F2-BB   (hex)               Valeo Vision Systems\r
+94F2BB     (base 16)           Valeo Vision Systems\r
+                               Dunmore Road\r
+                               Tuam  Co. Galway  H54 Y276\r
+                               IE\r
+\r
+64-20-E0   (hex)               T3 Technology Co., Ltd.\r
+6420E0     (base 16)           T3 Technology Co., Ltd.\r
+                               No.65/113, Chamnan Phenjati, 12A Floor, Rama9 road\r
+                               Bangkok  Bangkok  10310\r
+                               TH\r
+\r
+5C-C0-A0   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+5CC0A0     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+04-F3-52   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+04F352     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+EC-A1-D1   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+ECA1D1     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+A4-6D-A4   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+A46DA4     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+48-8B-0A   (hex)               Cisco Systems, Inc\r
+488B0A     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+24-94-CB   (hex)               ARRIS Group, Inc.\r
+2494CB     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+78-6A-1F   (hex)               ARRIS Group, Inc.\r
+786A1F     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+8C-7A-15   (hex)               Ruckus Wireless\r
+8C7A15     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+84-11-C2   (hex)               IEEE Registration Authority\r
+8411C2     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+28-AD-18   (hex)               Hui Zhou Gaoshengda Technology Co.,LTD\r
+28AD18     (base 16)           Hui Zhou Gaoshengda Technology Co.,LTD\r
+                               No.75,Zhongkai High-Tech Development District,Huizhou\r
+                               Hui Zhou  Guangdong  516006\r
+                               CN\r
+\r
+24-A4-87   (hex)               Huawei Device Co., Ltd.\r
+24A487     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+C4-5A-86   (hex)               Huawei Device Co., Ltd.\r
+C45A86     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+20-AC-9C   (hex)               China Telecom Corporation Limited\r
+20AC9C     (base 16)           China Telecom Corporation Limited\r
+                               31 Jinrong Street, Xicheng District, Beijing, China\r
+                               Beijing, China    100033\r
+                               CN\r
+\r
+74-78-27   (hex)               Dell Inc.\r
+747827     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
+\r
+10-96-93   (hex)               Amazon Technologies Inc.\r
+109693     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+E4-F1-D4   (hex)               vivo Mobile Communication Co., Ltd.\r
+E4F1D4     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
+                               CN\r
+\r
+94-09-D3   (hex)               shenzhen maxtopic technology co.,ltd\r
+9409D3     (base 16)           shenzhen maxtopic technology co.,ltd\r
+                               F3,Building 4, Ji'an Industrial Park, Songbai Blvd\r
+                               shenzhen  guangdong  518108\r
+                               CN\r
+\r
+58-D5-6E   (hex)               D-Link International\r
+58D56E     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+F4-8C-EB   (hex)               D-Link International\r
+F48CEB     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+EC-AD-E0   (hex)               D-Link International\r
+ECADE0     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+34-0A-33   (hex)               D-Link International\r
+340A33     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy\r
+                               Singapore   Singapore  609917\r
+                               SG\r
+\r
+BC-62-CE   (hex)               SHENZHEN NETIS TECHNOLOGY CO.,LTD\r
+BC62CE     (base 16)           SHENZHEN NETIS TECHNOLOGY CO.,LTD\r
+                               8 Floor, Bd B, information port, Langshan RD, Nanshan district, \r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+78-2E-56   (hex)               China Mobile Group Device Co.,Ltd.\r
+782E56     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street,Xicheng District\r
+                               Beijing    100053\r
+                               CN\r
+\r
+C4-0B-31   (hex)               Apple, Inc.\r
+C40B31     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+30-24-A9   (hex)               HP Inc.\r
+3024A9     (base 16)           HP Inc.\r
+                               10300 Energy Dr\r
+                               Spring  TX  77389\r
+                               US\r
+\r
+A8-6E-4E   (hex)               Huawei Device Co., Ltd.\r
+A86E4E     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+94-5F-34   (hex)               Renesas Electronics (Penang) Sdn. Bhd.\r
+945F34     (base 16)           Renesas Electronics (Penang) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
+\r
+60-3C-EE   (hex)               LG Electronics (Mobile Communications)\r
+603CEE     (base 16)           LG Electronics (Mobile Communications)\r
+                               60-39, Gasan-dong, Geumcheon-gu\r
+                               Seoul    153-801\r
+                               KR\r
+\r
+2C-4A-11   (hex)               Ciena Corporation\r
+2C4A11     (base 16)           Ciena Corporation\r
+                               7035 Ridge Road\r
+                               Hanover  MD  21076\r
+                               US\r
+\r
+1C-4C-48   (hex)               ITEL MOBILE LIMITED\r
+1C4C48     (base 16)           ITEL MOBILE LIMITED\r
+                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
+                               Hong Kong  KOWLOON  999077\r
+                               HK\r
+\r
+C4-CB-54   (hex)               Fibocom Auto Inc.\r
+C4CB54     (base 16)           Fibocom Auto Inc.\r
+                               5/F,Tower A,Technology Building II,1057# Nanhai Blvd\r
+                               Shenzhen  Guangdong  518054\r
+                               CN\r
+\r
+10-2D-31   (hex)               Shenzhen Americas Trading Company LLC\r
+102D31     (base 16)           Shenzhen Americas Trading Company LLC\r
+                               1308 Capital Ave.Suite #7\r
+                               Plano  TX  75074\r
+                               US\r
+\r
+2C-07-86   (hex)               Huawei Device Co., Ltd.\r
+2C0786     (base 16)           Huawei Device Co., Ltd.\r
+                               No.2 of Xincheng Road, Songshan Lake Zone\r
+                               Dongguan  Guangdong  523808\r
+                               CN\r
+\r
+0C-35-4F   (hex)               Nokia\r
+0C354F     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+60-81-2B   (hex)               Astronics Custom Control Concepts\r
+60812B     (base 16)           Astronics Custom Control Concepts\r
+                               6020 S 190th ST\r
+                               Kent  Washington  98032\r
+                               US\r
+\r
+F8-A7-3A   (hex)               Cisco Systems, Inc\r
+F8A73A     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+B8-11-4B   (hex)               Cisco Systems, Inc\r
+B8114B     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+30-E2-83   (hex)               Texas Instruments\r
+30E283     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+00-02-C7   (hex)               ALPSALPINE CO,.LTD\r
+0002C7     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi, Sama-City,\r
+                               Sama    00000\r
+                               JP\r
+\r
+FC-62-B9   (hex)               ALPSALPINE CO,.LTD\r
+FC62B9     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               kakuda-city  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+60-38-0E   (hex)               ALPSALPINE CO,.LTD\r
+60380E     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi\r
+                               Soma-city  Fukushima  976-8501\r
+                               JP\r
+\r
+28-A1-83   (hex)               ALPSALPINE CO,.LTD\r
+28A183     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-1E-3D   (hex)               ALPSALPINE CO,.LTD\r
+001E3D     (base 16)           ALPSALPINE CO,.LTD\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+48-F0-7B   (hex)               ALPSALPINE CO,.LTD\r
+48F07B     (base 16)           ALPSALPINE CO,.LTD\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-14-5A   (hex)               Westermo Neratec AG\r
+00145A     (base 16)           Westermo Neratec AG\r
+                               Rosswiesstrasse 29\r
+                               CH-8608  Bubikon  ZH\r
+                               CH\r
index 83657c6c32be6c678204cb2e2e5593f0d6ad62c1..cbfdf97c0232255c67762d207da96ddaa9a2a611 100644 (file)
@@ -983,9 +983,6 @@ B00000-BFFFFF     (base 16)         OPTiM Corporation
                                Saga    840-8502\r
                                JP\r
 \r
-34-04-9E   (hex)               Private\r
-C00000-CFFFFF     (base 16)            Private\r
-\r
 2C-48-35   (hex)               Phasor Solutions Ltd\r
 D00000-DFFFFF     (base 16)            Phasor Solutions Ltd\r
                                The Record Hall, 16 Baldwin Gardens\r
@@ -4022,6 +4019,186 @@ E00000-EFFFFF     (base 16)             KWANG YANG MOTOR CO.,LTD
                                Kaohsiung    807\r
                                TW\r
 \r
+CC-4F-5C   (hex)               Beijing Cotytech Technology Co.,LTD.\r
+C00000-CFFFFF     (base 16)            Beijing Cotytech Technology Co.,LTD.\r
+                               Rm2302,Block B,Haojing Building,Zhichunlu,Haidian District,Beijing\r
+                               Beijing    100192\r
+                               CN\r
+\r
+CC-4F-5C   (hex)               Smiths US Innovation LLC\r
+700000-7FFFFF     (base 16)            Smiths US Innovation LLC\r
+                               3125 SKYWAY CT\r
+                               Fremont  CA  94539\r
+                               US\r
+\r
+CC-4F-5C   (hex)               Watertech S.p.A.\r
+600000-6FFFFF     (base 16)            Watertech S.p.A.\r
+                               STRADA ANTICA FORNACE 2/4\r
+                               CANELLI  ITALY  14053\r
+                               IT\r
+\r
+CC-4F-5C   (hex)               Ontex BV\r
+B00000-BFFFFF     (base 16)            Ontex BV\r
+                               Genthof 5\r
+                               Buggenhout  NA  9255\r
+                               BE\r
+\r
+CC-4F-5C   (hex)               lesswire GmbH\r
+100000-1FFFFF     (base 16)            lesswire GmbH\r
+                               Rudower Chaussee 30\r
+                               Berlin  Germany  12489\r
+                               DE\r
+\r
+FC-CD-2F   (hex)               Ningbo Bull Digital Technology Co., LTD\r
+000000-0FFFFF     (base 16)            Ningbo Bull Digital Technology Co., LTD\r
+                               No.32 Sanhai Road, East Guanhaiwei Industrial zone\r
+                               Cixi City  Zhejiang   315314\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               QCTEK CO.,LTD.\r
+500000-5FFFFF     (base 16)            QCTEK CO.,LTD.\r
+                               6F., No.496, Bannan Rd., Zhonghe Dist., New Taipei City 235, Taiwan (R.O.C.)\r
+                               New Taipei City  New Taipei City  235\r
+                               TW\r
+\r
+CC-4F-5C   (hex)               Spark Biomedical\r
+400000-4FFFFF     (base 16)            Spark Biomedical\r
+                               4428 Irvin Simmons Drive\r
+                               Dallas  TX  75229\r
+                               US\r
+\r
+58-95-D8   (hex)               Shenzhen DOOGEE Hengtong Technology CO.,LTD\r
+000000-0FFFFF     (base 16)            Shenzhen DOOGEE Hengtong Technology CO.,LTD\r
+                               Shenzhen DOOGEE Hengtong Technology CO.,LTD\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               Astrogate Inc.\r
+700000-7FFFFF     (base 16)            Astrogate Inc.\r
+                               11F-6, No. 120, Qiaohe Rd., Zhonghe Dist.\r
+                               New Taipei City    235\r
+                               TW\r
+\r
+58-95-D8   (hex)               Loftie\r
+900000-9FFFFF     (base 16)            Loftie\r
+                               26 Grove St, Apt. 5C\r
+                               New York  NY  10014\r
+                               US\r
+\r
+58-95-D8   (hex)               Peak Communications Limited\r
+A00000-AFFFFF     (base 16)            Peak Communications Limited\r
+                               Suite 1, Commercial House One, Eden Island, Republic of Seychelles\r
+                               Eden Island    123\r
+                               SC\r
+\r
+58-95-D8   (hex)               LOCTEK ERGONOMIC TECHNOLOGY CORP.\r
+C00000-CFFFFF     (base 16)            LOCTEK ERGONOMIC TECHNOLOGY CORP.\r
+                               No. 588, Qihang South Road, Yinzhou Economic Development Zone\r
+                               Ningbo City  Zhejiang  315100\r
+                               CN\r
+\r
+58-95-D8   (hex)               Norgren Manufacturing Co., Ltd.\r
+600000-6FFFFF     (base 16)            Norgren Manufacturing Co., Ltd.\r
+                               Block 3, No 1885 Duhui Road, Minhang District\r
+                               Shanghai  Shanghai  201108\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               TATTILE SRL\r
+600000-6FFFFF     (base 16)            TATTILE SRL\r
+                               VIA DONIZETTI, 1/3/5\r
+                               MAIRANO  BRESCIA  25030\r
+                               IT\r
+\r
+DC-4A-9E   (hex)               Methodex Systems Pvt. Ltd.\r
+800000-8FFFFF     (base 16)            Methodex Systems Pvt. Ltd.\r
+                               607-8 Meghdoot, 94 Nehru Place\r
+                               New Delhi  Delhi  110019\r
+                               IN\r
+\r
+84-11-C2   (hex)               LLC STC MZTA\r
+400000-4FFFFF     (base 16)            LLC STC MZTA\r
+                               33/26 Mironovskaya str.\r
+                               Moscow  Moscow  115280\r
+                               RU\r
+\r
+84-11-C2   (hex)               Futurecom Systems Group\r
+200000-2FFFFF     (base 16)            Futurecom Systems Group\r
+                               3277 Langstaff Rd\r
+                               Concord  Ontario  L4K 5P8\r
+                               CA\r
+\r
+DC-4A-9E   (hex)               HAPPIEST BABY INC.\r
+D00000-DFFFFF     (base 16)            HAPPIEST BABY INC.\r
+                               3115 S La Cienega Blvd.\r
+                               Los Angeles  CA  90016\r
+                               US\r
+\r
+68-79-12   (hex)               Wingtech Mobile Communications Co., Ltd.\r
+A00000-AFFFFF     (base 16)            Wingtech Mobile Communications Co., Ltd.\r
+                               No.777,Yazhong Road,Nanhu District,\r
+                               Jiaxing  Zhejiang  314006\r
+                               CN\r
+\r
+68-79-12   (hex)               Swisscom Broadcast Ltd\r
+B00000-BFFFFF     (base 16)            Swisscom Broadcast Ltd\r
+                               Ostermundigenstrasse 99\r
+                               Bern    3050\r
+                               CH\r
+\r
+68-79-12   (hex)               CNDI CO.,LTD\r
+200000-2FFFFF     (base 16)            CNDI CO.,LTD\r
+                               33-13, EUNHAENG-RO, 218 BEON-GIL\r
+                               SIHEUNG-SI  GYEONGGI-DO  14908\r
+                               KR\r
+\r
+68-79-12   (hex)               Copper Labs, Inc.\r
+500000-5FFFFF     (base 16)            Copper Labs, Inc.\r
+                               3015 Sterling Circle #200\r
+                               Boulder  CO  80301\r
+                               US\r
+\r
+84-11-C2   (hex)               Kazdream Technologies LLP\r
+000000-0FFFFF     (base 16)            Kazdream Technologies LLP\r
+                               10, Turkestan Str.\r
+                               Nur-Sultan    010000\r
+                               KZ\r
+\r
+8C-47-6E   (hex)               HuiZhou MIKI Communication Equipment Co.,LTD\r
+200000-2FFFFF     (base 16)            HuiZhou MIKI Communication Equipment Co.,LTD\r
+                               NO.39,GuangTai Road HuiNan HI-techindustrial Park.Zhongkai Hi-tech Zone\r
+                               Huizhou    516000\r
+                               CN\r
+\r
+8C-47-6E   (hex)               Xertified AB\r
+900000-9FFFFF     (base 16)            Xertified AB\r
+                               Horisontvagen 60\r
+                               Stockholm  Stockholm  12830\r
+                               SE\r
+\r
+34-04-9E   (hex)               ClearCaptions LLC\r
+C00000-CFFFFF     (base 16)            ClearCaptions LLC\r
+                               595 Menlo Drive\r
+                               Rocklin   CA  95765\r
+                               US\r
+\r
+8C-47-6E   (hex)               Chipsafer Pte. Ltd.\r
+000000-0FFFFF     (base 16)            Chipsafer Pte. Ltd.\r
+                               2 Changi South Lane\r
+                               Singapore    486123\r
+                               SG\r
+\r
+8C-AE-49   (hex)               Gigawave\r
+A00000-AFFFFF     (base 16)            Gigawave\r
+                               Unit 4 Metro Business Park, ballycurreen\r
+                               cork    T12 HP60\r
+                               IE\r
+\r
+8C-AE-49   (hex)               Chengdu BillDTE Technology Co., Ltd\r
+600000-6FFFFF     (base 16)            Chengdu BillDTE Technology Co., Ltd\r
+                               Chengdu BiiDTE Technology Co.,Ltd\r
+                               Chengdu  Sichuan  610041\r
+                               CN\r
+\r
 4C-4B-F9   (hex)               Shenzhen dingsheng technology co., LTD\r
 400000-4FFFFF     (base 16)            Shenzhen dingsheng technology co., LTD\r
                                Floor 3, building 5, kaijeda industrial zone, no.97, huaxing road, langkou community, dalang street, longhua district\r
@@ -4508,9 +4685,6 @@ E0-5A-9F   (hex)          Link of Things Co., Ltd.
                                SAN DIEGO  CA  92123\r
                                US\r
 \r
-34-04-9E   (hex)               Private\r
-900000-9FFFFF     (base 16)            Private\r
-\r
 38-B8-EB   (hex)               Private\r
 700000-7FFFFF     (base 16)            Private\r
 \r
@@ -7676,12 +7850,6 @@ F4-69-D5   (hex)         Terminus (Shanghai) Technology Co.,Ltd.
                                Taipei City    10482\r
                                TW\r
 \r
-24-15-10   (hex)               Medicomp, Inc\r
-800000-8FFFFF     (base 16)            Medicomp, Inc\r
-                               \r
-                                   \r
-                               \r
-\r
 28-B7-7C   (hex)               Annapurna labs\r
 400000-4FFFFF     (base 16)            Annapurna labs\r
                                Matam Scientific Industries Center,   Building 8.2\r
@@ -7772,6 +7940,126 @@ A00000-AFFFFF     (base 16)             Sercomm Corporation.
                                Suzhou  Jiangsu  215000\r
                                CN\r
 \r
+58-20-8A   (hex)               Shangyin Intelligence Technology Shandong Co.,Ltd\r
+600000-6FFFFF     (base 16)            Shangyin Intelligence Technology Shandong Co.,Ltd\r
+                               2205,Building 2,Sanqingqisheng Square,No.1666,Xinluo Street\r
+                               Jinan  Shandong  250014\r
+                               CN\r
+\r
+58-20-8A   (hex)               Annapurna labs\r
+000000-0FFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
+\r
+58-20-8A   (hex)               UPM Technology, Inc\r
+E00000-EFFFFF     (base 16)            UPM Technology, Inc\r
+                               3000 NE Stucki ave ste #100\r
+                               Hillsboro    97124\r
+                               US\r
+\r
+CC-4F-5C   (hex)               Kymati GmbH\r
+500000-5FFFFF     (base 16)            Kymati GmbH\r
+                               Am Hochacker 5\r
+                               Grasbrunn    85630\r
+                               DE\r
+\r
+FC-CD-2F   (hex)               Loupedeck Oy\r
+200000-2FFFFF     (base 16)            Loupedeck Oy\r
+                               Museokatu 8 A 6\r
+                               Helsinki     00100\r
+                               FI\r
+\r
+FC-CD-2F   (hex)               Aroma Retail\r
+900000-9FFFFF     (base 16)            Aroma Retail\r
+                               5525 S. Valley View Blvd, ste 2\r
+                               Las Vegas  NV  89118\r
+                               US\r
+\r
+58-95-D8   (hex)               Sercomm Corporation.\r
+200000-2FFFFF     (base 16)            Sercomm Corporation.\r
+                               3F,No.81,Yu-Yih Rd.,Chu-Nan Chen\r
+                               Miao-Lih Hsuan    115\r
+                               TW\r
+\r
+DC-4A-9E   (hex)               LEACH INTERNATIONAL EUROPE\r
+300000-3FFFFF     (base 16)            LEACH INTERNATIONAL EUROPE\r
+                               2 RUE GOETHE\r
+                               SARRALBE  MOSELLE  57430\r
+                               FR\r
+\r
+DC-4A-9E   (hex)                LongSung Technology (Shanghai) Co.,Ltd.   \r
+A00000-AFFFFF     (base 16)             LongSung Technology (Shanghai) Co.,Ltd.   \r
+                                Room 606, Block B, Bldg. 1, No. 3000 Longdong Avenue., Zhangjiang Hi-Tech Park, Pudong District\r
+                               ShangHai    201203\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               Nuove Tecnologie srl\r
+500000-5FFFFF     (base 16)            Nuove Tecnologie srl\r
+                               VIALE RIMEMBRANZE 47/B, VAT N° IT10907840150\r
+                               Lainate  Milan  20045\r
+                               IT\r
+\r
+DC-4A-9E   (hex)               AiSight GmbH\r
+900000-9FFFFF     (base 16)            AiSight GmbH\r
+                               Gertraudenstr 10-12\r
+                               Berlin    10178\r
+                               DE\r
+\r
+84-11-C2   (hex)               Leybold GmbH\r
+800000-8FFFFF     (base 16)            Leybold GmbH\r
+                               Bonnerstr. 498\r
+                               Cologne     50968\r
+                               DE\r
+\r
+68-79-12   (hex)               Globus Infocom Limited\r
+C00000-CFFFFF     (base 16)            Globus Infocom Limited\r
+                               A 65, Sector 4, Noida\r
+                               Noida  U P  201301\r
+                               IN\r
+\r
+68-79-12   (hex)               Babbit and Friends, SIA\r
+700000-7FFFFF     (base 16)            Babbit and Friends, SIA\r
+                               Maiznicas iela 8 - 5\r
+                               Riga  Riga  LV1001\r
+                               LV\r
+\r
+68-79-12   (hex)               Ametek Solidstate Controls\r
+E00000-EFFFFF     (base 16)            Ametek Solidstate Controls\r
+                               875 DEARBORN DR\r
+                               COLUMBUS  OH  43085-1586\r
+                               US\r
+\r
+68-79-12   (hex)               LEAPS s.r.o.\r
+900000-9FFFFF     (base 16)            LEAPS s.r.o.\r
+                               Na rolich 655/8\r
+                               Praha 4  Czech  141 00\r
+                               CZ\r
+\r
+8C-47-6E   (hex)               AU Optronics Corporation\r
+A00000-AFFFFF     (base 16)            AU Optronics Corporation\r
+                               No. 1 Li-Hsin Rd. 2, Hsinchu Science Park\r
+                               Hsinchu 30078, Taiwan, R.O.C.    802\r
+                               TW\r
+\r
+8C-47-6E   (hex)               IntelliVIX Co. Ltd.\r
+800000-8FFFFF     (base 16)            IntelliVIX Co. Ltd.\r
+                               4, Hyoryeong-ro 34-gil, Seocho-gu\r
+                               Seoul    06704\r
+                               KR\r
+\r
+24-15-10   (hex)               Private\r
+800000-8FFFFF     (base 16)            Private\r
+                               \r
+                                   \r
+                               \r
+\r
+34-04-9E   (hex)               Church & Dwight Co., Inc.\r
+900000-9FFFFF     (base 16)            Church & Dwight Co., Inc.\r
+                               500 Charles Ewing Blvd\r
+                               Ewing  NJ  08628\r
+                               US\r
+\r
 20-85-93   (hex)               UNILUMIN GROUP CO.,LTD\r
 300000-3FFFFF     (base 16)            UNILUMIN GROUP CO.,LTD\r
                                No.112 Yongfu Rd.,BaoanDistrict,\r
@@ -8489,9 +8777,6 @@ A0-28-33   (hex)          IMESHX CORPORATION LIMITED
                                santa clara  CA  95050\r
                                US\r
 \r
-58-E8-76   (hex)               Private\r
-000000-0FFFFF     (base 16)            Private\r
-\r
 30-09-F9   (hex)               Beijing Mydreamplus Information Technology Co., Ltd.\r
 600000-6FFFFF     (base 16)            Beijing Mydreamplus Information Technology Co., Ltd.\r
                                Room 301-2, North Building, No. 11, CangJingGuan Lane, DongCheng District,\r
@@ -11603,12 +11888,162 @@ D00000-DFFFFF     (base 16)          StreamLocator
                                Richmond Hill  ON  L4B 2N1\r
                                CA\r
 \r
+58-20-8A   (hex)               Aggregate Co.,Ltd.\r
+300000-3FFFFF     (base 16)            Aggregate Co.,Ltd.\r
+                               Toso Building 4F, 1-9-8 Yayoi-cho\r
+                               nakano-ku  tokyo  164-0013\r
+                               JP\r
+\r
 18-FD-CB   (hex)               Gosuncn Technology Group Co.,LTD.\r
 400000-4FFFFF     (base 16)            Gosuncn Technology Group Co.,LTD.\r
                                6F,2819 KaiChuang Blvd.,Science Town,Huangpu District\r
                                Guangzhou City  Guangdong  510530\r
                                CN\r
 \r
+58-20-8A   (hex)               MARS DIGI TECH CO .,LTD\r
+200000-2FFFFF     (base 16)            MARS DIGI TECH CO .,LTD\r
+                               RM 2314,Build No.B2,GuiMiao Road,NanShan District\r
+                               ShenZhen  Guangdong  518054\r
+                               CN\r
+\r
+58-20-8A   (hex)               pureLiFi Ltd\r
+700000-7FFFFF     (base 16)            pureLiFi Ltd\r
+                               Rosebery House, 9 Haymarket Terrace\r
+                               Edinburgh    EH12 5EZ\r
+                               GB\r
+\r
+CC-4F-5C   (hex)               Feelmore Labs\r
+800000-8FFFFF     (base 16)            Feelmore Labs\r
+                               370 Jay Street, Floor 7\r
+                               Brooklyn  NY  11201\r
+                               US\r
+\r
+FC-CD-2F   (hex)               HEAD-DIRECT (KUNSHAN) Co. Ltd\r
+B00000-BFFFFF     (base 16)            HEAD-DIRECT (KUNSHAN) Co. Ltd\r
+                               Kunshan Bacheng West Yingbing Rd. shangkunzhichuang chanyeyuan C2#\r
+                               Suzhou  Jiangsu  215311\r
+                               CN\r
+\r
+58-E8-76   (hex)               Zhuhai Raysharp Technology Co.,Ltd\r
+000000-0FFFFF     (base 16)            Zhuhai Raysharp Technology Co.,Ltd\r
+                               No.100 of Keji Liu Rd.6, Hi-Tech Zone\r
+                               Zhuhai  Guangdong   519080\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               Asesorias y Servicios Innovaxxion SPA\r
+800000-8FFFFF     (base 16)            Asesorias y Servicios Innovaxxion SPA\r
+                               Alonso de Cordova 5320, of 1403, Las condes\r
+                               Santiago  RM  7550000\r
+                               CL\r
+\r
+FC-CD-2F   (hex)               Annapurna labs\r
+600000-6FFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
+\r
+FC-CD-2F   (hex)               Suzhou lehui display co.,ltd\r
+700000-7FFFFF     (base 16)            Suzhou lehui display co.,ltd\r
+                               ?225 Jinfeng Road?Suzhou New District?Jiangsu Province\r
+                               suzhou    215129\r
+                               CN\r
+\r
+58-95-D8   (hex)               Shenzhen C & D Electronics Co., Ltd.\r
+800000-8FFFFF     (base 16)            Shenzhen C & D Electronics Co., Ltd.\r
+                               9th FIoor, Building 9, No.1 Qingxiang road, BaoNeng Science and TechnoIogy Industrial Park, Longhua New District\r
+                               ShenZhen  GuangDong  518000\r
+                               CN\r
+\r
+58-95-D8   (hex)               Tonnet Telecommunication International Co., Ltd.\r
+300000-3FFFFF     (base 16)            Tonnet Telecommunication International Co., Ltd.\r
+                               10F,No.6,Ln.609,Sec.5 Chongxin Rd., Sanchong Dist.\r
+                               New Taipei    241\r
+                               TW\r
+\r
+FC-CD-2F   (hex)               Eltek brojila d.o.o.\r
+E00000-EFFFFF     (base 16)            Eltek brojila d.o.o.\r
+                               Svetice 24\r
+                               Zagreb    10000\r
+                               HR\r
+\r
+58-95-D8   (hex)               Gmv sistemas SAU\r
+E00000-EFFFFF     (base 16)            Gmv sistemas SAU\r
+                               C/ Juan Herrera 17 P.T.B. ,Parcela 101\r
+                               Boecillo  Valladolid  47151 \r
+                               ES\r
+\r
+58-95-D8   (hex)               Unity Surveillance, Inc.\r
+400000-4FFFFF     (base 16)            Unity Surveillance, Inc.\r
+                               629 East Grand Ave\r
+                               Hot Springs National Park  AR  71901\r
+                               US\r
+\r
+DC-4A-9E   (hex)               ADIAL\r
+400000-4FFFFF     (base 16)            ADIAL\r
+                               87 Rue Alexandre Fleming\r
+                               LISIEUX    14100\r
+                               FR\r
+\r
+DC-4A-9E   (hex)               Advanced Electronics Ltd\r
+100000-1FFFFF     (base 16)            Advanced Electronics Ltd\r
+                               Balliol Business Park\r
+                               Newcastle    NE12 8EW\r
+                               GB\r
+\r
+DC-4A-9E   (hex)               HEFEI DATANG STORAGE TECHNOLOGY CO.,LTD\r
+C00000-CFFFFF     (base 16)            HEFEI DATANG STORAGE TECHNOLOGY CO.,LTD\r
+                               7F BLOCK C J2 BUILDING INNOVATION PARK HIGH TECH DISTRICT\r
+                               HEFEI  AN HUI PROVINCE PR CHINA  220038\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               SES-imagotag Deutschland GmbH\r
+E00000-EFFFFF     (base 16)            SES-imagotag Deutschland GmbH\r
+                               Bundesstrasse 16\r
+                               Ettenheim  BW  77955\r
+                               DE\r
+\r
+84-11-C2   (hex)               KESSEL AG\r
+600000-6FFFFF     (base 16)            KESSEL AG\r
+                               Bahnhofstraße 31\r
+                               Lenting    85101\r
+                               DE\r
+\r
+84-11-C2   (hex)               igus GmbH\r
+A00000-AFFFFF     (base 16)            igus GmbH\r
+                               Spicher Str. 1a\r
+                               Köln    51147\r
+                               DE\r
+\r
+68-79-12   (hex)               Neurolab\r
+D00000-DFFFFF     (base 16)            Neurolab\r
+                               Naberezhnaya Shlyuzovaya, d. 6, str. 3, et. 3, pom. 1\r
+                               Moscow  -  115114\r
+                               RU\r
+\r
+68-79-12   (hex)               Annapurna labs\r
+100000-1FFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
+\r
+68-79-12   (hex)               McDonald's Corporation\r
+400000-4FFFFF     (base 16)            McDonald's Corporation\r
+                               110 N. Carpenter Street\r
+                               Chicago    60607\r
+                               US\r
+\r
+8C-47-6E   (hex)               Oxford Nanopore Technologies Ltd.\r
+600000-6FFFFF     (base 16)            Oxford Nanopore Technologies Ltd.\r
+                               Gosling Building, Edmund Halley Road, Oxford Science Park\r
+                               Oxford  Oxfordshire  OX4 4DQ\r
+                               GB\r
+\r
+8C-47-6E   (hex)               innolectric AG\r
+D00000-DFFFFF     (base 16)            innolectric AG\r
+                               Universitaetsstr. 136\r
+                               Bochum    44799 \r
+                               DE\r
+\r
 4C-4B-F9   (hex)               Shandong Linkotech Electronic Co., Ltd.\r
 600000-6FFFFF     (base 16)            Shandong Linkotech Electronic Co., Ltd.\r
                                22nd Floor, Building 2, Aosheng Building, No.1166 Xinyi Street, High-tech Zone\r
@@ -11639,9 +12074,6 @@ D00000-DFFFFF     (base 16)             StreamLocator
                                Los Gatos  CA  95032\r
                                US\r
 \r
-20-85-93   (hex)               Private\r
-900000-9FFFFF     (base 16)            Private\r
-\r
 24-15-10   (hex)               Topgolf Sweden AB\r
 900000-9FFFFF     (base 16)            Topgolf Sweden AB\r
                                Svärdvägen 11\r
@@ -15407,12 +15839,117 @@ C8-63-14   (hex)             Tymphany Acoustic Technology (Huizhou) Co.,  Ltd.
                                Huizhou  Guangdong  516223\r
                                CN\r
 \r
+58-20-8A   (hex)               SAMBO HITECH\r
+D00000-DFFFFF     (base 16)            SAMBO HITECH\r
+                               469,Seokjung-ro,Namdong-Gu\r
+                               Incheon    21501\r
+                               KR\r
+\r
 18-FD-CB   (hex)               Accel Robotics\r
 500000-5FFFFF     (base 16)            Accel Robotics\r
                                9160 KEARNY VILLA CT\r
                                San Diego  CA  92123\r
                                US\r
 \r
+58-20-8A   (hex)               Infodev Electronic Designers Intl.\r
+B00000-BFFFFF     (base 16)            Infodev Electronic Designers Intl.\r
+                               1995 rue Frank-Carrel Suite 202\r
+                               Quebec  Quebec  G1N4H9\r
+                               CA\r
+\r
+58-20-8A   (hex)               Conductix-Wampfler\r
+A00000-AFFFFF     (base 16)            Conductix-Wampfler\r
+                               10102 Fst\r
+                               omaha  NE  68127\r
+                               US\r
+\r
+58-20-8A   (hex)               JIA HUANG JHAN YE CO.,LTD\r
+500000-5FFFFF     (base 16)            JIA HUANG JHAN YE CO.,LTD\r
+                               1F., No. 19, Huanmei 2nd St., Donggang Township\r
+                               Plngtung County    928\r
+                               TW\r
+\r
+CC-4F-5C   (hex)               MatchX GmbH\r
+200000-2FFFFF     (base 16)            MatchX GmbH\r
+                               Adalbert Str.8\r
+                               Berlin    10999\r
+                               DE\r
+\r
+FC-CD-2F   (hex)               SCOPUS INTERNATIONAL-BELGIUM\r
+A00000-AFFFFF     (base 16)            SCOPUS INTERNATIONAL-BELGIUM\r
+                               Cable Centre, Raja International Building, \r
+                               Andamukkam, Kollam  Kerala  691 001\r
+                               IN\r
+\r
+58-95-D8   (hex)               Epiphan Systems Inc\r
+700000-7FFFFF     (base 16)            Epiphan Systems Inc\r
+                               400 March Rd Suite 510\r
+                               Ottawa  Ontario  K2K3H4\r
+                               CA\r
+\r
+FC-CD-2F   (hex)               Spedos ADS a.s.\r
+C00000-CFFFFF     (base 16)            Spedos ADS a.s.\r
+                               Hranická771\r
+                               Valašské Mezi?í?í    75701\r
+                               CZ\r
+\r
+58-95-D8   (hex)               SuZhou Ruishengwei Intelligent Technology Co.,Ltd\r
+B00000-BFFFFF     (base 16)            SuZhou Ruishengwei Intelligent Technology Co.,Ltd\r
+                               Room 507?Building 1?ZhongXuXin Science Park?NO.91?Weixin Road?Suzhou Industrial Park\r
+                               SuZhou  JiangSu  215021\r
+                               CN\r
+\r
+58-95-D8   (hex)               Alunos AG\r
+D00000-DFFFFF     (base 16)            Alunos AG\r
+                               Zugerstrasse\r
+                               Unteraegeri    6314\r
+                               CH\r
+\r
+20-85-93   (hex)               Mastodon Design\r
+900000-9FFFFF     (base 16)            Mastodon Design\r
+                               176 Anderson Ave, Suite F112\r
+                               Rochester  NY  14607\r
+                               US\r
+\r
+DC-4A-9E   (hex)               Dongguan Huili electroacoustic Industrial Co.,ltd\r
+000000-0FFFFF     (base 16)            Dongguan Huili electroacoustic Industrial Co.,ltd\r
+                               Dalang Town, Biyun Cai Bai Cun East Second Street 66,A4 Building 501\r
+                               Dongguan  Guangdong  523770\r
+                               CN\r
+\r
+84-11-C2   (hex)               Guangdong Creator&Flyaudio Electronic Technology Co.,LTD\r
+B00000-BFFFFF     (base 16)            Guangdong Creator&Flyaudio Electronic Technology Co.,LTD\r
+                               Block D1, No.3 Industrial Zone, Banxianshan, Hengli Town\r
+                               Dongguan  Guangdong  523460\r
+                               CN\r
+\r
+84-11-C2   (hex)               C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.\r
+900000-9FFFFF     (base 16)            C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.\r
+                               Teknopark ?stanbul, TGB, Sanayi Mah. Teknopark Bulvar?, No:1, Blok:1 Kat:2, Kurtköy-Pendik 34912, ?STANBUL\r
+                               Istanbul    34912\r
+                               TR\r
+\r
+84-11-C2   (hex)               Beijing Dayu Technology Co., Ltd.\r
+100000-1FFFFF     (base 16)            Beijing Dayu Technology Co., Ltd.\r
+                               11B-660, Building 13, Wangjing Xiyuan, Chaoyang\r
+                               Beijing    100000\r
+                               CN\r
+\r
+84-11-C2   (hex)               Hitachi,Ltd.\r
+300000-3FFFFF     (base 16)            Hitachi,Ltd.\r
+                               2-1,Shintoyofuta\r
+                               Kashiwa-shi  Chiba  277-0804\r
+                               JP\r
+\r
+84-11-C2   (hex)               Dangerous Music Group, LLC\r
+E00000-EFFFFF     (base 16)            Dangerous Music Group, LLC\r
+                               701 South Mountain Road\r
+                               New City  NY  10956\r
+                               US\r
+\r
+8C-47-6E   (hex)               Private\r
+700000-7FFFFF     (base 16)            Private\r
+\r
 20-85-93   (hex)               Great Lite International\r
 700000-7FFFFF     (base 16)            Great Lite International\r
                                11F., No.207-2, Sec. 3, Beixin Rd., Xindian Dist.,\r
@@ -19250,14 +19787,182 @@ B00000-BFFFFF     (base 16)          TRANSLITE GLOBAL LLC
                                Vienna    1210\r
                                AT\r
 \r
+58-20-8A   (hex)               SAMIL CTS Co., Ltd.\r
+800000-8FFFFF     (base 16)            SAMIL CTS Co., Ltd.\r
+                               8F, Woolim Lion's Valley 3cha, 24 Dunchon Daero 388beon-gil, Jungwon-gu\r
+                               Seongnam-si  Gyeonggi-do, KOREA  13403\r
+                               KR\r
+\r
 18-FD-CB   (hex)               ENERGIE IP\r
 700000-7FFFFF     (base 16)            ENERGIE IP\r
                                48 rue du Château d’eau \r
                                Paris  Ile-de-France  75010\r
                                FR\r
 \r
-58-20-8A   (hex)               SAMIL CTS Co., Ltd.\r
-800000-8FFFFF     (base 16)            SAMIL CTS Co., Ltd.\r
-                               8F, Woolim Lion's Valley 3cha, 24 Dunchon Daero 388beon-gil, Jungwon-gu\r
-                               Seongnam-si  Gyeonggi-do, KOREA  13403\r
-                               KR\r
+CC-4F-5C   (hex)               Shanghai Zenchant Electornics Co.,LTD\r
+300000-3FFFFF     (base 16)            Shanghai Zenchant Electornics Co.,LTD\r
+                               Room 1202, building a, Noble international, 908 Xiuwen Road, Minhang District\r
+                               ShangHai  ShangHai  201199\r
+                               CN\r
+\r
+CC-4F-5C   (hex)               Dtrovision\r
+900000-9FFFFF     (base 16)            Dtrovision\r
+                               22-10 STATE RT 208\r
+                               Fair Lawn  NJ  07410\r
+                               US\r
+\r
+CC-4F-5C   (hex)               AZ-TECHNOLOGY SDN BHD\r
+A00000-AFFFFF     (base 16)            AZ-TECHNOLOGY SDN BHD\r
+                               A108 & A109 BLOCK A KELANA BUSINESS CENTRE NO: 97 JALAN SS7/2 KELANA JAYA\r
+                               PETALING JAYA  SELANGOR  47301\r
+                               MY\r
+\r
+CC-4F-5C   (hex)               Buttons (Beijing) Technology Limited\r
+E00000-EFFFFF     (base 16)            Buttons (Beijing) Technology Limited\r
+                               Room 202, Floor 2, Building No. 3, No. 9 Xiaoying Road, Chaoyang District\r
+                               Beijing    100101\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               Shenzhen Smartbyte Technology Co., Ltd.\r
+D00000-DFFFFF     (base 16)            Shenzhen Smartbyte Technology Co., Ltd.\r
+                                6th Floor, Building D, Huiqing Science and Technology Park, No. 8 Dafu Industrial Zone, Guanlan Street, Longhua District, Shenzhen\r
+                               shenzhen  guangdong  518110\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               Siren Care(Shanghai) information and technology company\r
+100000-1FFFFF     (base 16)            Siren Care(Shanghai) information and technology company\r
+                               Room 205, Floor 2, B Zone, Building 2, No 1899, Jiahao Rd, Jiading\r
+                               Shanghai    201802\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               Xmitech Technology Co., Limited\r
+300000-3FFFFF     (base 16)            Xmitech Technology Co., Limited\r
+                               RM888, F8,Tower B,Xinnengyuan Building\r
+                               shenzhen    518054\r
+                               CN\r
+\r
+FC-CD-2F   (hex)               Genitek Engineering sprl\r
+400000-4FFFFF     (base 16)            Genitek Engineering sprl\r
+                               Rue Edouard Belin, 5\r
+                               Mont-Saint-Guibert    1435\r
+                               BE\r
+\r
+58-95-D8   (hex)               shenzhen UDD Technologies,co.,Ltd\r
+100000-1FFFFF     (base 16)            shenzhen UDD Technologies,co.,Ltd\r
+                               Unit D, 6th Floor, Jialitai Bldg., No.45 Yanshan Road, Shekou, Nanshan District, Shenzhen, China\r
+                               shenzhen  guangdong  51800\r
+                               CN\r
+\r
+58-95-D8   (hex)               elgris UG\r
+500000-5FFFFF     (base 16)            elgris UG\r
+                               Langerweher Str. 10\r
+                               Inden  Deutschland  52459\r
+                               DE\r
+\r
+CC-4F-5C   (hex)               Beijing Neutron Technology CO.,LTD.\r
+D00000-DFFFFF     (base 16)            Beijing Neutron Technology CO.,LTD.\r
+                               Beijing Neutron Technology CO.,LTD. \r
+                               Beijing  Beijing  100193\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               Maxvision Technology Corp.\r
+B00000-BFFFFF     (base 16)            Maxvision Technology Corp.\r
+                               16F,East Block,High-tech Plaza Phase II,Tianan Cyber Park,Futian District,Shenzhen.\r
+                               Shenzhen.    518000\r
+                               CN\r
+\r
+DC-4A-9E   (hex)               Annapurna labs\r
+200000-2FFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
+\r
+84-11-C2   (hex)               Provision-ISR\r
+C00000-CFFFFF     (base 16)            Provision-ISR\r
+                               11 Atir Yeda St.\r
+                               Kfar Saba  Israel  4464310\r
+                               IL\r
+\r
+84-11-C2   (hex)               Goldmund Switzerland\r
+D00000-DFFFFF     (base 16)            Goldmund Switzerland\r
+                               Chemin Grenet 21, 1214\r
+                               Vernier  Geneva  1214\r
+                               CH\r
+\r
+84-11-C2   (hex)               AIBIoT GmbH\r
+500000-5FFFFF     (base 16)            AIBIoT GmbH\r
+                               Hornemannstr. 12\r
+                               Hildesheim  Lower Saxony  31137\r
+                               DE\r
+\r
+84-11-C2   (hex)               Ei3 Corporation\r
+700000-7FFFFF     (base 16)            Ei3 Corporation\r
+                               2 Blue Hill Plaza, Ste 1544\r
+                               Pearl River  NY  10965\r
+                               US\r
+\r
+68-79-12   (hex)               Stephan Electronics SARL\r
+300000-3FFFFF     (base 16)            Stephan Electronics SARL\r
+                               Maupas 9\r
+                               Lausanne    1004\r
+                               CH\r
+\r
+68-79-12   (hex)               ShangHai Aigentoo Information Technology Co., Ltd\r
+800000-8FFFFF     (base 16)            ShangHai Aigentoo Information Technology Co., Ltd\r
+                               Room 1126,Building 1,Xin Ye Building,388 Tianlin Road,Xuhui District\r
+                               Shanghai    200080\r
+                               CN\r
+\r
+68-79-12   (hex)               APPOTRONICS CO., LTD\r
+600000-6FFFFF     (base 16)            APPOTRONICS CO., LTD\r
+                               4th Floor,SZICC,NO.1089,Chaguang Road,Nanshan District, Shenzhen, China\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+68-79-12   (hex)               PCTEL, Inc.\r
+000000-0FFFFF     (base 16)            PCTEL, Inc.\r
+                               471 Brighton Drive\r
+                               Bloomingdale  IL  60108\r
+                               US\r
+\r
+8C-47-6E   (hex)               Shanghai Satellite Communication Technology Co.,Ltd\r
+300000-3FFFFF     (base 16)            Shanghai Satellite Communication Technology Co.,Ltd\r
+                               Shanghai Satellite Communication Technology Co.,Ltd\r
+                               Shanghai  Shanghai  201800\r
+                               CN\r
+\r
+8C-47-6E   (hex)               Square Inc.\r
+500000-5FFFFF     (base 16)            Square Inc.\r
+                               1455 Market St.\r
+                               San Francisco  CA  94103\r
+                               US\r
+\r
+8C-47-6E   (hex)               Faravid Communication&Data Analysis\r
+B00000-BFFFFF     (base 16)            Faravid Communication&Data Analysis\r
+                               18th unit, No.2, Houman Alley Abbaspour Av., \r
+                               Vanak Sq.  Tehran  1435633413\r
+                               IR\r
+\r
+8C-47-6E   (hex)               Edge Networks Inc\r
+C00000-CFFFFF     (base 16)            Edge Networks Inc\r
+                               943 W. Overland Road, Suite 152\r
+                               Meridian  ID  83642\r
+                               US\r
+\r
+8C-47-6E   (hex)               TelWare Corporation\r
+100000-1FFFFF     (base 16)            TelWare Corporation\r
+                               1824 Industrial Center Circle\r
+                               Charlotte  NC  28213\r
+                               US\r
+\r
+8C-47-6E   (hex)               Shenzhen Juding Electronics Co., Ltd.\r
+400000-4FFFFF     (base 16)            Shenzhen Juding Electronics Co., Ltd.\r
+                               5th Floor, Building B5, Fenghuanggang Third Industrial Zone, No.231, Baotian 1st Road, Baoan District\r
+                               Shenzhen  Guangdong  518100\r
+                               CN\r
+\r
+8C-47-6E   (hex)               Annapurna labs\r
+E00000-EFFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
index 4931652249d308a00b674dcfacd0be9574014b70..f7d37444cac068fca0f36d3880a6373385564f3b 100644 (file)
@@ -80,12 +80,6 @@ F3E000-F3EFFF     (base 16)          ООО РОНЕКС
                                Buchlovice    68708\r
                                CZ\r
 \r
-70-B3-D5   (hex)               C Tech Bilişim Teknolojileri San. ve Tic. AŞ\r
-DCD000-DCDFFF     (base 16)            C Tech Bilişim Teknolojileri San. ve Tic. AŞ\r
-                               Teknopark İstanbul, TGB, Sanayi Mah. Teknopark Bulvarı, No:1, Blok:1 Kat:2, Kurtköy-Pendik 34912, İSTANBUL\r
-                               Istanbul    34912\r
-                               TR\r
-\r
 70-B3-D5   (hex)               BRS Sistemas Eletrônicos\r
 356000-356FFF     (base 16)            BRS Sistemas Eletrônicos\r
                                Rua Gomes de Freitas, 491 / 204\r
@@ -2795,12 +2789,6 @@ BF2000-BF2FFF     (base 16)              TWIN DEVELOPMENT
                                Miami  FL  33131\r
                                US\r
 \r
-70-B3-D5   (hex)               GRIDSMART Technologies\r
-7EC000-7ECFFF     (base 16)            GRIDSMART Technologies\r
-                               10545 Hardin Valley Rd\r
-                               Knoxville  TN  37932\r
-                               US\r
-\r
 70-B3-D5   (hex)               ChamSys Ltd\r
 0BE000-0BEFFF     (base 16)            ChamSys Ltd\r
                                Unit 3B Richmond Works, Pitt Road\r
@@ -4571,12 +4559,6 @@ C0D000-C0DFFF     (base 16)              Clarity Medical Pvt Ltd
                                Neusaess  Bayern  85356\r
                                DE\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-261000-261FFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
 70-B3-D5   (hex)               Shangnuo company\r
 82B000-82BFFF     (base 16)            Shangnuo company\r
                                Nong'an district\r
@@ -4619,6 +4601,150 @@ A1A000-A1AFFF     (base 16)             Nueon - The COR
                                Menlo Park    94025\r
                                US\r
 \r
+70-B3-D5   (hex)               ABL Space Systems\r
+F7F000-F7FFFF     (base 16)            ABL Space Systems\r
+                               224 Oregon St\r
+                               El Segundo  CA  90245\r
+                               US\r
+\r
+70-B3-D5   (hex)               DUEVI SRL\r
+F41000-F41FFF     (base 16)            DUEVI SRL\r
+                               VIA BARD 12/A\r
+                               TORINO  TORINO  10142\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Daifuku CO., Ltd.\r
+3A2000-3A2FFF     (base 16)            Daifuku CO., Ltd.\r
+                               1225 Nakazaiji, Hino-cho, Gamo-gun, Shiga\r
+                               Gamo-gun  Shiga-ken  529-1692\r
+                               JP\r
+\r
+70-B3-D5   (hex)               CLARESYS LIMITED\r
+485000-485FFF     (base 16)            CLARESYS LIMITED\r
+                               154E Brook Drive, Milton Park\r
+                               Abingdon    OX14 4SD\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Elmeasure India Pvt Ltd\r
+93D000-93DFFF     (base 16)            Elmeasure India Pvt Ltd\r
+                               No.47-P, KIADB Hardware Park, Huvinayakanahalli\r
+                               Bengaluru  Karnataka  562149\r
+                               IN\r
+\r
+70-B3-D5   (hex)               Panamera\r
+7B1000-7B1FFF     (base 16)            Panamera\r
+                               Rua. Dr. Brasilio Vicente de Castro, 111\r
+                               Critiba  Parana  81200-526\r
+                               BR\r
+\r
+70-B3-D5   (hex)               QUNU LABS PRIVATE LIMITED\r
+9A6000-9A6FFF     (base 16)            QUNU LABS PRIVATE LIMITED\r
+                               Centenary Building, 2nd Floor,, East Wing, No. 28 M.G. Road\r
+                               BANGALORE  KARNATAKA  560025\r
+                               IN\r
+\r
+70-B3-D5   (hex)               ALTIT.CO.,Ltd.\r
+552000-552FFF     (base 16)            ALTIT.CO.,Ltd.\r
+                               Gasan Digital 1 ro 88, 1905\r
+                               Seoul  Korea  08590\r
+                               KR\r
+\r
+70-B3-D5   (hex)               Harman Connected Services Corporation India Pvt. Ltd.\r
+423000-423FFF     (base 16)            Harman Connected Services Corporation India Pvt. Ltd.\r
+                               Plot No 3 & 3A, EOIZ Industrial Area, Sy.No.85 and 86, KIADB, Whitefield,\r
+                               Bengaluru  Karnataka  560066\r
+                               IN\r
+\r
+70-B3-D5   (hex)               Galaxy Next Generation, Inc.\r
+E1D000-E1DFFF     (base 16)            Galaxy Next Generation, Inc.\r
+                               285 Big A Rd \r
+                               Toccoa  GA  30577\r
+                               US\r
+\r
+70-B3-D5   (hex)               Gigaband IP LLC\r
+E9F000-E9FFFF     (base 16)            Gigaband IP LLC\r
+                               85 N Brookside St\r
+                               Chandler  AZ  85225\r
+                               US\r
+\r
+70-B3-D5   (hex)               Intrinsic Group Limited\r
+663000-663FFF     (base 16)            Intrinsic Group Limited\r
+                               The Maltings\r
+                               Allendale  Northumberland  NE47 9EE\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Barcelona Smart Technologies\r
+D5E000-D5EFFF     (base 16)            Barcelona Smart Technologies\r
+                               C/Joaquim Molins 5\r
+                               Barcelona  Catalunya  08028\r
+                               ES\r
+\r
+70-B3-D5   (hex)               C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.\r
+DCD000-DCDFFF     (base 16)            C TECH BILISIM TEKNOLOJILERI SAN. VE TIC. A.S.\r
+                               Teknopark İstanbul, TGB, Sanayi Mah. Teknopark Bulvarı, No:1, Blok:1 Kat:2, Kurtköy-Pendik 34912, İSTANBUL\r
+                               Istanbul    34912\r
+                               TR\r
+\r
+70-B3-D5   (hex)               TableConnect GmbH\r
+7BD000-7BDFFF     (base 16)            TableConnect GmbH\r
+                               Schlossgasse 13/2/3\r
+                               Vienna  Vienna  1050\r
+                               AT\r
+\r
+70-B3-D5   (hex)               Cubic ITS, Inc. dba GRIDSMART Technologies\r
+7EC000-7ECFFF     (base 16)            Cubic ITS, Inc. dba GRIDSMART Technologies\r
+                               10545 Hardin Valley Rd\r
+                               Knoxville  TN  37932\r
+                               US\r
+\r
+70-B3-D5   (hex)               Eldes Ltd\r
+8B6000-8B6FFF     (base 16)            Eldes Ltd\r
+                               Ukmerges 283b\r
+                               Vilnius    LT-06313\r
+                               LT\r
+\r
+70-B3-D5   (hex)               Foerster-Technik GmbH\r
+453000-453FFF     (base 16)            Foerster-Technik GmbH\r
+                               Gerwigstraße 25\r
+                               Engen  Baden-Württemberg  78234\r
+                               DE\r
+\r
+70-B3-D5   (hex)               BTG Instruments AB\r
+D85000-D85FFF     (base 16)            BTG Instruments AB\r
+                               Industrigatan 1-3\r
+                               Saffle  Varmland  66132\r
+                               SE\r
+\r
+70-B3-D5   (hex)               Circle Consult ApS\r
+23D000-23DFFF     (base 16)            Circle Consult ApS\r
+                               Rundforbivej 271A\r
+                               Naerum    2850\r
+                               DK\r
+\r
+70-B3-D5   (hex)               CreevX\r
+BF4000-BF4FFF     (base 16)            CreevX\r
+                               158A Staffordstown Rd\r
+                               Randalstown  Antrim  BT41 3LH\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+261000-261FFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Velvac Incorporated\r
+44F000-44FFFF     (base 16)            Velvac Incorporated\r
+                               2405 S. Calhoun Road\r
+                               New Berlin  WI  53151-2709\r
+                               US\r
+\r
+70-B3-D5   (hex)               Connido Limited\r
+71D000-71DFFF     (base 16)            Connido Limited\r
+                               35 Kingsland Road\r
+                               London    E2 8AA\r
+                               GB\r
+\r
 70-B3-D5   (hex)               EVCO SPA\r
 A80000-A80FFF     (base 16)            EVCO SPA\r
                                VIA FELTRE N. 81\r
@@ -9251,24 +9377,18 @@ D53000-D53FFF     (base 16)             BeiLi eTek (Zhangjiagang) Co., Ltd.
                                Meersburg    88709\r
                                DE\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-1BE000-1BEFFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-B9A000-B9AFFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
 70-B3-D5   (hex)               ABECO Industrie Computer GmbH\r
 F02000-F02FFF     (base 16)            ABECO Industrie Computer GmbH\r
                                Industriestrasse 2\r
                                Straelen  NRW  47638\r
                                DE\r
 \r
+70-B3-D5   (hex)               Abbott Diagnostics Technologies AS\r
+DDE000-DDEFFF     (base 16)            Abbott Diagnostics Technologies AS\r
+                               P. O.  Box 6863 Rodeløkka\r
+                               Oslo  Oslo  0504\r
+                               NO\r
+\r
 70-B3-D5   (hex)               PuS GmbH und Co. KG\r
 09D000-09DFFF     (base 16)            PuS GmbH und Co. KG\r
                                Hainstr. 13\r
@@ -9281,6 +9401,147 @@ F02000-F02FFF     (base 16)             ABECO Industrie Computer GmbH
                                Taipei     114\r
                                TW\r
 \r
+70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
+B22000-B22FFF     (base 16)            YUYAMA MFG Co.,Ltd\r
+                               1-4-30\r
+                               MEISHINGUCHI,TOYONAKA  OSAKA  561-0841\r
+                               JP\r
+\r
+70-B3-D5   (hex)               Laser Imagineering Vertriebs GmbH\r
+3EE000-3EEFFF     (base 16)            Laser Imagineering Vertriebs GmbH\r
+                               Rudolf-Diesel-Weg 5\r
+                               Moelln    23879\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Guan Show Technologe Co., Ltd.\r
+1BA000-1BAFFF     (base 16)            Guan Show Technologe Co., Ltd.\r
+                               No.127, Jianguo 1st Rd., Lingya Dist.\r
+                                Kaohsiung City     802\r
+                               TW\r
+\r
+70-B3-D5   (hex)               Serveron / Qualitrol\r
+B1C000-B1CFFF     (base 16)            Serveron / Qualitrol\r
+                               13550 SW Karl Braun Drive\r
+                               Beaverton  OR  97005\r
+                               US\r
+\r
+70-B3-D5   (hex)               Gentec\r
+83D000-83DFFF     (base 16)            Gentec\r
+                               2625 Dalton\r
+                               Quebec    G1P 3S9\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Xirgo Technologies LLC\r
+1A2000-1A2FFF     (base 16)            Xirgo Technologies LLC\r
+                               188 Camino Ruiz\r
+                               Camarillo  CA  93012\r
+                               US\r
+\r
+70-B3-D5   (hex)               HAN CHANG\r
+859000-859FFF     (base 16)            HAN CHANG\r
+                               171, Gasan digital 1-ro, Geumcheon-gu, Seoul, Republic of Korea\r
+                               Seoul  Geumcheon-gu, Seoul  08503\r
+                               KR\r
+\r
+70-B3-D5   (hex)               Daatrics LTD\r
+B69000-B69FFF     (base 16)            Daatrics LTD\r
+                               4th Floor, 86-90 Paul Street\r
+                               LONDON    EC2A 4NE\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Guangdong Transtek Medical Electronics Co., Ltd.\r
+8D4000-8D4FFF     (base 16)            Guangdong Transtek Medical Electronics Co., Ltd.\r
+                               Zone A, No.105, Dongli Road, Torch Development District\r
+                               Zhongshan  Guangdong  528437\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Williams Sound LLC\r
+58B000-58BFFF     (base 16)            Williams Sound LLC\r
+                               10300 Valley View Road\r
+                               Eden Prairie  MN  55344\r
+                               US\r
+\r
+70-B3-D5   (hex)               BrainboxAI Inc\r
+E44000-E44FFF     (base 16)            BrainboxAI Inc\r
+                               2075 boul Robert-Bourassa, Suite 500\r
+                               MONTREAL  QUEBEC  H3A 2L1\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Cardinal Kinetic\r
+09C000-09CFFF     (base 16)            Cardinal Kinetic\r
+                               2748 Circleport Drive\r
+                               Erlanger  KY  41018\r
+                               US\r
+\r
+70-B3-D5   (hex)               Sicon srl\r
+6C8000-6C8FFF     (base 16)            Sicon srl\r
+                               Via Sila 1/3\r
+                               Isola Vicentina  Vicenza  36033\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Private\r
+A31000-A31FFF     (base 16)            Private\r
+\r
+70-B3-D5   (hex)               Clockwork Dog\r
+5D7000-5D7FFF     (base 16)            Clockwork Dog\r
+                               43 Philpot Street\r
+                               London    E1 2JH\r
+                               GB\r
+\r
+70-B3-D5   (hex)               SUN ELECTRONICS CO.,LTD.\r
+D82000-D82FFF     (base 16)            SUN ELECTRONICS CO.,LTD.\r
+                               667-2,Furugori,Misato-machi,Kodama-gun\r
+                               Saitama-ken    367-0111\r
+                               JP\r
+\r
+70-B3-D5   (hex)               BIRTECH TECHNOLOGY\r
+E65000-E65FFF     (base 16)            BIRTECH TECHNOLOGY\r
+                               Ak is Business Center, Tuzla, Istanbul / Turkey\r
+                               Istanbul  Tuzla  34944\r
+                               TR\r
+\r
+70-B3-D5   (hex)               Transit Solutions, LLC.\r
+E68000-E68FFF     (base 16)            Transit Solutions, LLC.\r
+                               114 West Grandview Avenue\r
+                               Zelienople  PA  16063\r
+                               US\r
+\r
+70-B3-D5   (hex)               Nuance Hearing Ltd.\r
+35B000-35BFFF     (base 16)            Nuance Hearing Ltd.\r
+                               Raoul Wallenberg 24, Building A1, Floor 3\r
+                               Tel Aviv    6971920\r
+                               IL\r
+\r
+70-B3-D5   (hex)               xTom GmbH\r
+8B5000-8B5FFF     (base 16)            xTom GmbH\r
+                               Kreuzstr.60\r
+                               Duesseldorf  NRW  40210\r
+                               DE\r
+\r
+70-B3-D5   (hex)               E-Controls\r
+6E2000-6E2FFF     (base 16)            E-Controls\r
+                               PASSATGE GARROTXA, 6\r
+                               SANT BOI DE LLOBREGAT    08830\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+B9A000-B9AFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+1BE000-1BEFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Integrated Protein Technologies, Inc.\r
+FAC000-FACFFF     (base 16)            Integrated Protein Technologies, Inc.\r
+                               PO box 1839\r
+                               Evanston  IL  60204\r
+                               US\r
+\r
 70-B3-D5   (hex)               System West dba ICS Electronics\r
 E06000-E06FFF     (base 16)            System West dba ICS Electronics\r
                                7034 Commerce Circle Suite A\r
@@ -9593,9 +9854,6 @@ AEC000-AECFFF     (base 16)               Paratec Ltd.
                                Daejeon    34016\r
                                KR\r
 \r
-70-B3-D5   (hex)               Private\r
-A03000-A03FFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               Insitu Inc.\r
 D36000-D36FFF     (base 16)            Insitu Inc.\r
                                901 E Bingen Point Way\r
@@ -9806,9 +10064,6 @@ E0C000-E0CFFF     (base 16)              Communication Systems Solutions
 70-B3-D5   (hex)               Private\r
 591000-591FFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               Private\r
-376000-376FFF     (base 16)            Private\r
-\r
 00-1B-C5   (hex)               Corporate Systems Engineering \r
 015000-015FFF     (base 16)            Corporate Systems Engineering \r
                                1215 Brookville Way\r
@@ -9821,9 +10076,6 @@ E0C000-E0CFFF     (base 16)              Communication Systems Solutions
                                Three Rivers  MI  49093\r
                                US\r
 \r
-70-B3-D5   (hex)               Private\r
-738000-738FFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               Ya Batho Trading (Pty) Ltd\r
 AE6000-AE6FFF     (base 16)            Ya Batho Trading (Pty) Ltd\r
                                9 Estee Ackerman Street\r
@@ -9836,9 +10088,6 @@ AE6000-AE6FFF     (base 16)              Ya Batho Trading (Pty) Ltd
                                Kyoto City  Kyoto-fu  604-8411\r
                                JP\r
 \r
-70-B3-D5   (hex)               Private\r
-B71000-B71FFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               Engage Technologies\r
 977000-977FFF     (base 16)            Engage Technologies\r
                                7041 Boone Avenue North\r
@@ -12431,12 +12680,6 @@ A4B000-A4BFFF     (base 16)            McKay Brothers LLC
                                Oakland  CA  94612\r
                                US\r
 \r
-70-B3-D5   (hex)               Energybox Limited\r
-FA4000-FA4FFF     (base 16)            Energybox Limited\r
-                               4901 Central Plaza, 18 Harbour Road\r
-                               Wanchai  Hong Kong  0000\r
-                               HK\r
-\r
 70-B3-D5   (hex)               OrbiWise SA\r
 078000-078FFF     (base 16)            OrbiWise SA\r
                                c/o Fongit\r
@@ -13778,12 +14021,6 @@ D7D000-D7DFFF     (base 16)            BESO sp. z o.o.
                                Brzeg Dolny    56-120\r
                                PL\r
 \r
-70-B3-D5   (hex)               PCTEL\r
-ED2000-ED2FFF     (base 16)            PCTEL\r
-                               22600 gateway center drive, Suite 100\r
-                               Clarksburg  MD  20871\r
-                               US\r
-\r
 70-B3-D5   (hex)               Computechnic AG\r
 7D4000-7D4FFF     (base 16)            Computechnic AG\r
                                Rietlistrasse 3\r
@@ -13886,18 +14123,6 @@ A23000-A23FFF     (base 16)            LG Electronics
                                SEOUL    07796\r
                                KR\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-C17000-C17FFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-70C000-70CFFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
 70-B3-D5   (hex)               Antlia Systems\r
 416000-416FFF     (base 16)            Antlia Systems\r
                                401 N Michigan Ave Ste 1200\r
@@ -13934,6 +14159,228 @@ E11000-E11FFF     (base 16)           Engage Technologies
                                Macleod  VIC  3085\r
                                AU\r
 \r
+70-B3-D5   (hex)               Season Electronics Ltd\r
+0F5000-0F5FFF     (base 16)            Season Electronics Ltd\r
+                               600 Nest Business Park \r
+                               Havant  Hampshire  PO9 5TL\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Proemion GmbH\r
+A03000-A03FFF     (base 16)            Proemion GmbH\r
+                               Donaustraße 14\r
+                               Fulda  Hessen  36043\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Magenta Labs, Inc.\r
+376000-376FFF     (base 16)            Magenta Labs, Inc.\r
+                               164 Townsend Street Unit 1\r
+                               San Francisco  CA  94107\r
+                               US\r
+\r
+70-B3-D5   (hex)               AC Power Corp.\r
+49C000-49CFFF     (base 16)            AC Power Corp.\r
+                               3F, No.200, Gangqian Rd., Neihu District\r
+                               Taipei City    11494\r
+                               TW\r
+\r
+70-B3-D5   (hex)               Technological Ray GmbH\r
+4D7000-4D7FFF     (base 16)            Technological Ray GmbH\r
+                               Zeppelinstraße 1\r
+                               Hösbach  Bayern  63768\r
+                               DE\r
+\r
+70-B3-D5   (hex)               PCS Inc.\r
+622000-622FFF     (base 16)            PCS Inc.\r
+                               4974 Provident Drive\r
+                               Cincinnati  OH  45246\r
+                               US\r
+\r
+70-B3-D5   (hex)               GRYPHON SECURE INC\r
+738000-738FFF     (base 16)            GRYPHON SECURE INC\r
+                               1015 - 2225 SHEPPARD AVE E\r
+                               TORONTO  ONTARIO  M2J 5C2\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Beringar\r
+6EF000-6EFFFF     (base 16)            Beringar\r
+                               citypoint - 65 Haymarket Terrace\r
+                               Edinburgh  Lothian  EH12 5HD\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Satsky Communication Equipment Co.,Ltd.\r
+247000-247FFF     (base 16)            Satsky Communication Equipment Co.,Ltd.\r
+                               6/F., 710 building, Liantang Pengji Industrial Zone,Luohu District\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+70-B3-D5   (hex)               LITUM BILGI TEKNOLOJILERI SAN. VE TIC. A.S.\r
+483000-483FFF     (base 16)            LITUM BILGI TEKNOLOJILERI SAN. VE TIC. A.S.\r
+                               ?evket Özçelik Sk. No:29 Kültür Mah. Litum Plaza\r
+                               IZMIR    35220\r
+                               TR\r
+\r
+70-B3-D5   (hex)               Shanghai Hourui Technology Co., Ltd.\r
+9A3000-9A3FFF     (base 16)            Shanghai Hourui Technology Co., Ltd.\r
+                               Room A1001A,Building A,No.1618 Yishan Road\r
+                               Shanghai    201103\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Optiver Pty Ltd\r
+B71000-B71FFF     (base 16)            Optiver Pty Ltd\r
+                               39 HUNTER ST\r
+                               SYDNEY  NSW  2000\r
+                               AU\r
+\r
+70-B3-D5   (hex)               GEGA ELECTRONIQUE\r
+573000-573FFF     (base 16)            GEGA ELECTRONIQUE\r
+                               1 RUE SAINT ELOI\r
+                               MONTCEAU LES MINES  SAONE ET LOIRE  71300\r
+                               FR\r
+\r
+70-B3-D5   (hex)               DAVE SRL\r
+27B000-27BFFF     (base 16)            DAVE SRL\r
+                               VIA TALPONEDO 29/A\r
+                               PORCIA  PORDENONE  330850\r
+                               IT\r
+\r
+70-B3-D5   (hex)               ZAO ZEO\r
+619000-619FFF     (base 16)            ZAO ZEO\r
+                               Khachaturiana 14a\r
+                               Moscow    127562\r
+                               RU\r
+\r
+70-B3-D5   (hex)               Nuand LLC\r
+7D8000-7D8FFF     (base 16)            Nuand LLC\r
+                               680 Mission Street #41H\r
+                               San Francisco  CA  94105\r
+                               US\r
+\r
+70-B3-D5   (hex)               Jinga-hi, Inc.\r
+9BB000-9BBFFF     (base 16)            Jinga-hi, Inc.\r
+                               20303 Clifden Way\r
+                               CUPERTINO  CA  95014\r
+                               US\r
+\r
+70-B3-D5   (hex)               SeaTech Intelligent Technology (Shanghai) Co., LTD\r
+380000-380FFF     (base 16)            SeaTech Intelligent Technology (Shanghai) Co., LTD\r
+                               5th Flr,7Bldg,No.518,Xinzhuan Road\r
+                               Shanghai  Shanghai  201612\r
+                               CN\r
+\r
+70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
+8FB000-8FBFFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
+                               Winnettener Straße 6\r
+                               Dinkelsbuehl  Bavaria  91550\r
+                               DE\r
+\r
+70-B3-D5   (hex)               ABC Electric Co.\r
+3C8000-3C8FFF     (base 16)            ABC Electric Co.\r
+                               Room 266, 1333 Road Xinlong\r
+                               Shanghai    201101\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Senquire Pte. Ltd\r
+962000-962FFF     (base 16)            Senquire Pte. Ltd\r
+                               12, Bedok Reservoir View,, 17-37\r
+                               Singapore  Singapore  479237\r
+                               SG\r
+\r
+70-B3-D5   (hex)               WILMORE ELECTRONICS COMPANY\r
+ED4000-ED4FFF     (base 16)            WILMORE ELECTRONICS COMPANY\r
+                               607 US HIGHWAY 70A E\r
+                               HILLSBOROUGH  NC  27278-8526\r
+                               US\r
+\r
+70-B3-D5   (hex)               Cubic ITS, Inc. dba GRIDSMART Technologies\r
+CBF000-CBFFFF     (base 16)            Cubic ITS, Inc. dba GRIDSMART Technologies\r
+                               10545 Hardin Valley Rd\r
+                               Knoxville  TN  37932\r
+                               US\r
+\r
+70-B3-D5   (hex)               Veo Robotics, Inc.\r
+6C4000-6C4FFF     (base 16)            Veo Robotics, Inc.\r
+                               411 Waverley Oaks Rd. Suite 107\r
+                               Waltham  MA  02452\r
+                               US\r
+\r
+70-B3-D5   (hex)               PCTEL, Inc.\r
+ED2000-ED2FFF     (base 16)            PCTEL, Inc.\r
+                               22600 gateway center drive, Suite 100\r
+                               Clarksburg  MD  20871\r
+                               US\r
+\r
+70-B3-D5   (hex)               Energybox Limited\r
+FA4000-FA4FFF     (base 16)            Energybox Limited\r
+                               8/F., Green 18, HK Science Park\r
+                               Sha Tin  Hong Kong   0000\r
+                               HK\r
+\r
+70-B3-D5   (hex)               eBZ GmbH\r
+C57000-C57FFF     (base 16)            eBZ GmbH\r
+                               Neusser Straße 8\r
+                               Bielefeld  NRW  33649\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Teneo IoT B.V.\r
+CDD000-CDDFFF     (base 16)            Teneo IoT B.V.\r
+                               Landbouwstraat 5-06\r
+                               Winterswijk    7101 EK\r
+                               NL\r
+\r
+70-B3-D5   (hex)               tetronik GmbH AEN\r
+909000-909FFF     (base 16)            tetronik GmbH AEN\r
+                               Silberbachstr.10\r
+                               Taunusstein  Hessen  65232\r
+                               DE\r
+\r
+70-B3-D5   (hex)               EBE Mobility & Green Energy GmbH\r
+624000-624FFF     (base 16)            EBE Mobility & Green Energy GmbH\r
+                               Prießnitzgasse 16\r
+                               Mödling  Austria  2340\r
+                               AT\r
+\r
+70-B3-D5   (hex)               WuXi anktech Co., Ltd \r
+B61000-B61FFF     (base 16)            WuXi anktech Co., Ltd \r
+                               Room1801, No.6 Third Financial Street, Binhu District, Wuxi City, Jiangsu Province\r
+                               Wuxi  jiangsu  214000\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Power Element \r
+D17000-D17FFF     (base 16)            Power Element \r
+                               Verkhnyaya Krasnoselskaya 2/1\r
+                               Moscow  moscow  107140\r
+                               RU\r
+\r
+70-B3-D5   (hex)               ISRV Zrt.\r
+AB1000-AB1FFF     (base 16)            ISRV Zrt.\r
+                                Löv?ház utca 2-6. IV. emelet\r
+                               Budapest  PEST  1024 \r
+                               HU\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+70C000-70CFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+C17000-C17FFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Boundary Technologies Ltd\r
+BBC000-BBCFFF     (base 16)            Boundary Technologies Ltd\r
+                               61 Dublin Street\r
+                               Edinburgh  Midlothian  EH3 6NL\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Microvision\r
+5F5000-5F5FFF     (base 16)            Microvision\r
+                               272, Digital-ro, 1004ho Microvision.\r
+                               Guro-gu, Seoul, Republic of Korea    08848\r
+                               KR\r
+\r
 70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
 BBB000-BBBFFF     (base 16)            YUYAMA MFG Co.,Ltd\r
                                3-3-1\r
@@ -14504,12 +14951,6 @@ A5D000-A5DFFF     (base 16)            Position Imaging
                                Bristol    BS1 2PH\r
                                GB\r
 \r
-70-B3-D5   (hex)               GRIDSMART Technologies\r
-D50000-D50FFF     (base 16)            GRIDSMART Technologies\r
-                               10545 Hardin Valley Rd\r
-                               Knoxville  TN  37932\r
-                               US\r
-\r
 70-B3-D5   (hex)               Shenzhen Siera Technology Ltd\r
 1BD000-1BDFFF     (base 16)            Shenzhen Siera Technology Ltd\r
                                Room 2039, Shenhai Building, Wanzhong Village, Bulong Road, Minzhi, Longhua district,  City: Shenzhen\r
@@ -14747,9 +15188,6 @@ C64000-C64FFF     (base 16)             SYS TEC electronic GmbH
                                Taipei City  Taiwan  115-73\r
                                TW\r
 \r
-70-B3-D5   (hex)               Private\r
-E22000-E22FFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               H3D, Inc.\r
 3F2000-3F2FFF     (base 16)            H3D, Inc.\r
                                812 Avis Drive\r
@@ -15089,9 +15527,6 @@ BB9000-BB9FFF     (base 16)             KOSMEK.Ltd
                                Marlborough    SN8 1LH\r
                                GB\r
 \r
-70-B3-D5   (hex)               Private\r
-DE9000-DE9FFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               ST Aerospace Systems\r
 27F000-27FFFF     (base 16)            ST Aerospace Systems\r
                                505A Airport Road Paya Lebar\r
@@ -18446,12 +18881,6 @@ DBA000-DBAFFF     (base 16)            KODENSHI CORP.
                                Carouge    1227\r
                                CH\r
 \r
-70-B3-D5   (hex)               Cubitech\r
-B86000-B86FFF     (base 16)            Cubitech\r
-                               4-6 Kiprou str\r
-                               Tavros  Athens  17778\r
-                               GR\r
-\r
 70-B3-D5   (hex)               CDS Institute of Management Strategy, Inc.\r
 3A3000-3A3FFF     (base 16)            CDS Institute of Management Strategy, Inc.\r
                                Fukuyoshi-cho Billding 7F, Roppongi 2-2-6\r
@@ -18608,12 +19037,6 @@ C1E000-C1EFFF     (base 16)            Kron Medidores
                                São Paulo  São Paulo  04760-020\r
                                BR\r
 \r
-70-B3-D5   (hex)               Yokogawa Denshikiki Co.,Ltd\r
-7F0000-7F0FFF     (base 16)            Yokogawa Denshikiki Co.,Ltd\r
-                               Minami Shinjuku Hoshino Bldg.  5-23-13 Sendagaya\r
-                               Shibuya-ku  Tokyo  151-0051\r
-                               JP\r
-\r
 70-B3-D5   (hex)               IK MULTIMEDIA PRODUCTION SRL\r
 2FB000-2FBFFF     (base 16)            IK MULTIMEDIA PRODUCTION SRL\r
                                Via dell'Industria 46\r
@@ -18662,12 +19085,6 @@ D14000-D14FFF     (base 16)            LIGPT
                                New Delhi    110019\r
                                IN\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-A1B000-A1BFFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
 70-B3-D5   (hex)               Melissa Climate Jsc\r
 2DD000-2DDFFF     (base 16)            Melissa Climate Jsc\r
                                Gen. Gurko 4 Street\r
@@ -18680,12 +19097,216 @@ AE8000-AE8FFF     (base 16)          Innoknight
                                Hsinchu    300\r
                                TW\r
 \r
+70-B3-D5   (hex)               NUBURU Inc.\r
+DC7000-DC7FFF     (base 16)            NUBURU Inc.\r
+                               7442 S. Tucson Way\r
+                               Centennial  CO  80112\r
+                               US\r
+\r
+70-B3-D5   (hex)               Vigorcloud Co., Ltd.\r
+A3E000-A3EFFF     (base 16)            Vigorcloud Co., Ltd.\r
+                               3F., No. 11, Xinpo 1st St., Xindian Dist.,\r
+                               New Taipei City    231\r
+                               TW\r
+\r
+70-B3-D5   (hex)               Tornado Modular Systems\r
+40C000-40CFFF     (base 16)            Tornado Modular Systems\r
+                               Inzhenernaya st. 4a\r
+                               Novosibirsk  Novosibirsk  630128\r
+                               RU\r
+\r
+70-B3-D5   (hex)               SECUREAN CO.,Ltd\r
+10B000-10BFFF     (base 16)            SECUREAN CO.,Ltd\r
+                               danny@securean.com\r
+                               Incheon  2nd floor, 16 Giljuro, Seogu  22793\r
+                               KR\r
+\r
 70-B3-D5   (hex)               Projects Unlimited Inc.\r
 7C5000-7C5FFF     (base 16)            Projects Unlimited Inc.\r
                                6300 Sand Lake Road\r
                                Dayton  OH  45414\r
                                US\r
 \r
+70-B3-D5   (hex)               RFHIC\r
+25E000-25EFFF     (base 16)            RFHIC\r
+                               41-14, Burim-ro 170beon-gil\r
+                               Dongan-gu, Anyang-si  Gyeonggi-do  14055\r
+                               KR\r
+\r
+70-B3-D5   (hex)               Hilo\r
+B86000-B86FFF     (base 16)            Hilo\r
+                               4-6 Kiprou str\r
+                               Tavros  Athens  17778\r
+                               GR\r
+\r
+70-B3-D5   (hex)               Federated Wireless, Inc. \r
+E22000-E22FFF     (base 16)            Federated Wireless, Inc. \r
+                               4301 North Fairfax Drive, Suite 310 \r
+                               Arlington   VA  22203\r
+                               US\r
+\r
+70-B3-D5   (hex)               Nocix, LLC\r
+BE2000-BE2FFF     (base 16)            Nocix, LLC\r
+                               201 East 16th Ave\r
+                               North Kansas City  MO  64116\r
+                               US\r
+\r
+70-B3-D5   (hex)               ADDE\r
+79C000-79CFFF     (base 16)            ADDE\r
+                               21 impasse frédéric faÿs\r
+                               Villeurbanne    69100\r
+                               FR\r
+\r
+70-B3-D5   (hex)               DEUTA-WERKE GmbH\r
+F6B000-F6BFFF     (base 16)            DEUTA-WERKE GmbH\r
+                               Paffrather Str. 140\r
+                               Bergisch Gladbach  North Rhine-Westphalia  51465\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Servotronix Motion Control\r
+B0E000-B0EFFF     (base 16)            Servotronix Motion Control\r
+                               21C Yagia Kapayim st.\r
+                               Petach Tikva     49130\r
+                               IL\r
+\r
+70-B3-D5   (hex)               Matrix Telematics Limited\r
+B83000-B83FFF     (base 16)            Matrix Telematics Limited\r
+                               Merlin Court, Atlantic Street\r
+                               Altrincham  Cheshire  WA14 5NL\r
+                               GB\r
+\r
+70-B3-D5   (hex)               STACKFORCE GmbH\r
+E87000-E87FFF     (base 16)            STACKFORCE GmbH\r
+                               Biengener Str. 3\r
+                               Eschbach    79427\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Qlinx Technologies\r
+EC9000-EC9FFF     (base 16)            Qlinx Technologies\r
+                               1717 N Street NW Ste 1\r
+                               Washington  DC  20036\r
+                               US\r
+\r
+70-B3-D5   (hex)               Pantherun Technologies Pvt Ltd\r
+B14000-B14FFF     (base 16)            Pantherun Technologies Pvt Ltd\r
+                               311 6th main road Hal 2nd stage\r
+                               Bangalore  Karnataka  560038\r
+                               IN\r
+\r
+70-B3-D5   (hex)               Liberator Pty Ltd\r
+561000-561FFF     (base 16)            Liberator Pty Ltd\r
+                               265?Gilbert Street\r
+                               Adelaide     SA 5000\r
+                               AU\r
+\r
+70-B3-D5   (hex)               EASTERN SCIENCE & TECHNOLOGY CO., LTD\r
+2DF000-2DFFFF     (base 16)            EASTERN SCIENCE & TECHNOLOGY CO., LTD\r
+                               6F.,No.963, Zhongzheng Rd, Zhonghe Dist.\r
+                               New Taipei City    235\r
+                               TW\r
+\r
+70-B3-D5   (hex)               Imenco Ltd\r
+3D1000-3D1FFF     (base 16)            Imenco Ltd\r
+                               Campus 1 Innovation Park, Balgownie Road\r
+                               Bridge of Don  Aberdeen  AB22 8GT\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Contec Americas Inc.\r
+883000-883FFF     (base 16)            Contec Americas Inc.\r
+                               3991 Sarno Rd\r
+                               Melbourne  FL  32934\r
+                               US\r
+\r
+70-B3-D5   (hex)               Hon Hai Precision IND.CO.,LTD\r
+B45000-B45FFF     (base 16)            Hon Hai Precision IND.CO.,LTD\r
+                               No. 66 Chung Shan Road TU-Cheng Industrial district TAIPEI TAIWAN \r
+                               TAIPEI  TAIWAN  33859\r
+                               CN\r
+\r
+70-B3-D5   (hex)               International Super Computer Co., Ltd.\r
+806000-806FFF     (base 16)            International Super Computer Co., Ltd.\r
+                               807-3, 8 / F, block F, No. 9, Shangdi Third Street, Haidian District\r
+                               Beijing    100085\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Rivercity Innovations Ltd.\r
+156000-156FFF     (base 16)            Rivercity Innovations Ltd.\r
+                               116 Research Drive, Suit 217\r
+                               Saskatoon  Saskatchewan  S7N 3R3\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Cubic ITS, Inc. dba GRIDSMART Technologies\r
+D50000-D50FFF     (base 16)            Cubic ITS, Inc. dba GRIDSMART Technologies\r
+                               10545 Hardin Valley Rd\r
+                               Knoxville  TN  37932\r
+                               US\r
+\r
+70-B3-D5   (hex)               myenergi Ltd\r
+3A6000-3A6FFF     (base 16)            myenergi Ltd\r
+                               Church View Business Centre, Binbrook\r
+                               Market Rasen  Lincolnshire  LN8 6BY\r
+                               GB\r
+\r
+70-B3-D5   (hex)               eumig industrie-TV GmbH.\r
+C46000-C46FFF     (base 16)            eumig industrie-TV GmbH.\r
+                               Gewerbeparkstrasse 9\r
+                               Anif  Salzburg  5081\r
+                               AT\r
+\r
+70-B3-D5   (hex)               IWS Global Pty Ltd\r
+8F9000-8F9FFF     (base 16)            IWS Global Pty Ltd\r
+                               29 Oxleigh Dr\r
+                               Perth  Western Australia  6090\r
+                               AU\r
+\r
+70-B3-D5   (hex)               SERTEC SRL\r
+621000-621FFF     (base 16)            SERTEC SRL\r
+                               VIA LOMBARDIA, 7/8\r
+                               BUSSOLENGO   VERONA  37012\r
+                               IT\r
+\r
+70-B3-D5   (hex)               QDevil\r
+921000-921FFF     (base 16)            QDevil\r
+                               Fruebjergvej 3\r
+                               København Ø    2100\r
+                               DK\r
+\r
+70-B3-D5   (hex)               Macromatic Industrial Controls, Inc.\r
+118000-118FFF     (base 16)            Macromatic Industrial Controls, Inc.\r
+                               W134N5345 Campbell Drive\r
+                               Menomonee Falls  WI  53051\r
+                               US\r
+\r
+70-B3-D5   (hex)               EA Elektroautomatik GmbH & Co. KG\r
+4C3000-4C3FFF     (base 16)            EA Elektroautomatik GmbH & Co. KG\r
+                               Helmholtzstraße 31-33\r
+                               Viersen  NRW  41747\r
+                               DE\r
+\r
+70-B3-D5   (hex)               EkspertStroyProekt LLC\r
+DE9000-DE9FFF     (base 16)            EkspertStroyProekt LLC\r
+                               office 400, str.61, d.2/4, Luzhnetskaya nab.\r
+                               Moscow  Moscow  119270\r
+                               RU\r
+\r
+70-B3-D5   (hex)               YDK Technologies Co.,Ltd\r
+7F0000-7F0FFF     (base 16)            YDK Technologies Co.,Ltd\r
+                               Minami Shinjuku Hoshino Bldg.  5-23-13 Sendagaya\r
+                               Shibuya-ku  Tokyo  151-0051\r
+                               JP\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+A1B000-A1BFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+BEB000-BEBFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
 70-B3-D5   (hex)               DISMUNTEL SAL\r
 92C000-92CFFF     (base 16)            DISMUNTEL SAL\r
                                Pol ind cotes\r
@@ -23288,24 +23909,6 @@ F59000-F59FFF     (base 16)            KOREA SPECTRAL PRODUCTS
                                Palo Alto  CA  94303\r
                                US\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-7A4000-7A4FFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-832000-832FFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-F5D000-F5DFFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               5757 Phantom Drive, Suite 125\r
-                               Hazelwood  MO  63042\r
-                               US\r
-\r
 70-B3-D5   (hex)               KMtronic ltd\r
 6D6000-6D6FFF     (base 16)            KMtronic ltd\r
                                Dobri Czintulov 28A str.\r
@@ -23335,3 +23938,129 @@ F5D000-F5DFFF     (base 16)           Potter Electric Signal Co. LLC
                                No. 25, Tianrong road, Tianliao second industrial park, Yutang street, Guangming new district\r
                                Shenzhen  Guangdong   518132\r
                                CN\r
+\r
+70-B3-D5   (hex)               CAST Group of Companies Inc.\r
+BDE000-BDEFFF     (base 16)            CAST Group of Companies Inc.\r
+                               35 Ripley Ave.\r
+                               Toronto  Ontario  M6S3P2\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Momentum Data Systems\r
+116000-116FFF     (base 16)            Momentum Data Systems\r
+                               5432 Bolsa Ave Unit B\r
+                               Huntington Beach  CA  92649\r
+                               US\r
+\r
+70-B3-D5   (hex)               Camozzi Automation SpA\r
+3AB000-3ABFFF     (base 16)            Camozzi Automation SpA\r
+                               Via Eritrea 20/I\r
+                               BRESCIA  ITALY  25080\r
+                               IT\r
+\r
+70-B3-D5   (hex)               PuS GmbH und Co. KG\r
+322000-322FFF     (base 16)            PuS GmbH und Co. KG\r
+                               Hainstr. 13\r
+                               Gera  Germany  07545\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Ci4Rail\r
+195000-195FFF     (base 16)            Ci4Rail\r
+                               Vogelweiherstrasse 20\r
+                               Nürnberg  Bavaria  90441\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Arris\r
+988000-988FFF     (base 16)            Arris\r
+                               2500 Walsh Ave.\r
+                               Santa Clara  CA  95014\r
+                               US\r
+\r
+70-B3-D5   (hex)               Xirgo Technologies LLC\r
+646000-646FFF     (base 16)            Xirgo Technologies LLC\r
+                               188 Camino Ruiz\r
+                               Camarillo  CA  93012\r
+                               US\r
+\r
+70-B3-D5   (hex)               Transit Solutions, LLC.\r
+4E2000-4E2FFF     (base 16)            Transit Solutions, LLC.\r
+                               114 West Grandview Avenue\r
+                               Zelienople  PA  16063\r
+                               US\r
+\r
+70-B3-D5   (hex)               JD Squared, Inc.\r
+562000-562FFF     (base 16)            JD Squared, Inc.\r
+                               915 Riverview Drive\r
+                               Johnson City  TN  37601\r
+                               US\r
+\r
+70-B3-D5   (hex)               VOCAL Technologies Ltd.\r
+7B5000-7B5FFF     (base 16)            VOCAL Technologies Ltd.\r
+                               520 LEE ENTRANCE STE 202\r
+                               BUFFALO  NY  142282583\r
+                               US\r
+\r
+70-B3-D5   (hex)               Deltronic Security AB\r
+CEC000-CECFFF     (base 16)            Deltronic Security AB\r
+                               E A Rosengrensgata 4\r
+                               Västra Frölunda    421 31\r
+                               SE\r
+\r
+70-B3-D5   (hex)               Atman Tecnologia Ltda\r
+F90000-F90FFF     (base 16)            Atman Tecnologia Ltda\r
+                               Avenida Adalberto Simão Nader\r
+                               Vitória  Espírito Santo  29070-010\r
+                               BR\r
+\r
+70-B3-D5   (hex)               Shenyang TECHE Technology Co.,Ltd\r
+47D000-47DFFF     (base 16)            Shenyang TECHE Technology Co.,Ltd\r
+                               oom2302, Changfeng building, 26-2 Pangjiang street, Dadong District\r
+                               Shenyang  Liaoning  110041\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Öresundskraft AB\r
+668000-668FFF     (base 16)            Öresundskraft AB\r
+                               Västra Sandgatan 4\r
+                               Helsingborg    25225\r
+                               SE\r
+\r
+70-B3-D5   (hex)               Omsk Manufacturing Association named after A.S. Popov\r
+A61000-A61FFF     (base 16)            Omsk Manufacturing Association named after A.S. Popov\r
+                               10 Let Oktyabrya str, 195\r
+                               Omsk    644009\r
+                               RU\r
+\r
+70-B3-D5   (hex)               DELITECH GROUP\r
+018000-018FFF     (base 16)            DELITECH GROUP\r
+                               425 Rue du Trident\r
+                               VENDARGUES    34740\r
+                               FR\r
+\r
+70-B3-D5   (hex)               Larraioz Elektronika\r
+176000-176FFF     (base 16)            Larraioz Elektronika\r
+                               FACT Larraioz, Ctra GI3162 km 2,2\r
+                               Zarautz    20800\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+7A4000-7A4FFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+F5D000-F5DFFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+832000-832FFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood  MO  63042\r
+                               US\r
+\r
+70-B3-D5   (hex)               ICsec S.A.\r
+395000-395FFF     (base 16)            ICsec S.A.\r
+                               Wichrowa 1A\r
+                               Poznan    60-446\r
+                               PL\r
index 025133416f6e23c23ce64f1dfad9bc96f0d84a76..4174c7598ffb9cb86d25ed5854d57b516b4aafeb 100755 (executable)
@@ -32,7 +32,7 @@ try:
     from pyparsing import (Word, White, Literal, ParserElement, Regex, LineEnd,
                            OneOrMore, Combine, Or, Optional, Suppress, Group,
                            nums, alphanums, printables,
-                           stringEnd, pythonStyleComment, QuotedString,
+                           stringEnd, pythonStyleComment,
                            ParseBaseException)
 except ImportError:
     print('pyparsing is not available')
@@ -54,7 +54,6 @@ EOL = LineEnd().suppress()
 EMPTYLINE = LineEnd()
 COMMENTLINE = pythonStyleComment + EOL
 INTEGER = Word(nums)
-STRING =  QuotedString('"')
 REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
 SIGNED_REAL = Combine(Optional(Word('-+')) + REAL)
 UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
@@ -94,7 +93,8 @@ def hwdb_grammar():
     matchline = (matchline_typed | matchline_general) + EOL
 
     propertyline = (White(' ', exact=1).suppress() +
-                    Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) +
+                    Combine(UDEV_TAG - '=' - Optional(Word(alphanums + '_=:@*.!-;, "'))
+                            - Optional(pythonStyleComment)) +
                     EOL)
     propertycomment = White(' ', exact=1) + pythonStyleComment + EOL
 
@@ -114,6 +114,7 @@ def property_grammar():
     dpi_setting = (Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*')
     mount_matrix_row = SIGNED_REAL + ',' + SIGNED_REAL + ',' + SIGNED_REAL
     mount_matrix = (mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX')
+    xkb_setting = Optional(Word(alphanums + '+-/@._'))
 
     props = (('MOUSE_DPI', Group(OneOrMore(dpi_setting))),
              ('MOUSE_WHEEL_CLICK_ANGLE', INTEGER),
@@ -138,9 +139,9 @@ def property_grammar():
              ('POINTINGSTICK_CONST_ACCEL', REAL),
              ('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
              ('ID_INPUT_TOUCHPAD_INTEGRATION', Or(('internal', 'external'))),
-             ('XKB_FIXED_LAYOUT', STRING),
-             ('XKB_FIXED_VARIANT', STRING),
-             ('XKB_FIXED_MODEL', STRING),
+             ('XKB_FIXED_LAYOUT', xkb_setting),
+             ('XKB_FIXED_VARIANT', xkb_setting),
+             ('XKB_FIXED_MODEL', xkb_setting),
              ('KEYBOARD_LED_NUMLOCK', Literal('0')),
              ('KEYBOARD_LED_CAPSLOCK', Literal('0')),
              ('ACCEL_MOUNT_MATRIX', mount_matrix),
@@ -201,8 +202,9 @@ def check_matches(groups):
             except ParseBaseException as e:
                 error('Pattern {!r} is invalid: {}', rest, e)
                 continue
-            if rest[-1] not in '*:':
-                error('pattern {} does not end with "*" or ":"', match)
+
+        if not rest.endswith(':*'):
+            error("pattern {!r} does not end with ':*'", match)
 
     matches.sort()
     prev = None
index c9e82ed908a228986899821cff9916072ea49bcf..e1dc3da818b8dca8157323acde8e5860459ff4f8 100644 (file)
@@ -1,8 +1,8 @@
 #
 #      List of PCI ID's
 #
-#      Version: 2020.07.21
-#      Date:    2020-07-21 03:15:02
+#      Version: 2020.10.11
+#      Date:    2020-10-11 03:15:01
 #
 #      Maintained by Albert Pool, Martin Mares, and other volunteers from
 #      the PCI ID Project at https://pci-ids.ucw.cz/.
                1000 9363  MegaRAID SAS 9361-4i
                1000 9364  MegaRAID SAS 9364-8i
                1000 936a  MegaRAID SAS 9364-8i
+               1000 9380  MegaRAID SAS 9380-8e
                1028 1f41  PERC H830 Adapter
                1028 1f42  PERC H730P Adapter
                1028 1f43  PERC H730 Adapter
                1028 200b  HBA355i Adapter
                1028 200c  HBA355i Front
                1028 200d  HBA355e Adapter
-               1028 200e  HBA355i MX
+               1028 200e  HBA350i MX
                1d49 0205  ThinkSystem 440-16i SAS/SATA PCIe Gen4 12Gb Internal HBA
                1d49 0206  ThinkSystem 440-16e SAS/SATA PCIe Gen4 12Gb HBA
        00e7  Fusion-MPT 12GSAS/PCIe Unsupported SAS38xx
        13e9  Ariel
        1478  Navi 10 XL Upstream Port of PCI Express Switch
        1479  Navi 10 XL Downstream Port of PCI Express Switch
-       154c  Kryptos
+       154c  Kryptos [Radeon RX 350]
        154e  Garfield
        1551  Arlene
        1552  Pooky
        3154  RV380/M24 GL [Mobility FireGL V3200]
        3155  RV380 GL [FireMV 2400]
        3171  RV380 GL [FireMV 2400] (Secondary)
-       3e50  RV380 [Radeon X600]
+       3e50  RV380 [Radeon X550/X600]
        3e54  RV380 GL [FireGL V3200]
-       3e70  RV380 [Radeon X600] (Secondary)
+       3e70  RV380 [Radeon X550/X600] (Secondary)
        4136  RS100 [Mobility IGP 320M]
        4137  RS200 [Radeon IGP 340]
        4144  R300 [Radeon 9500]
        5044  All-In-Wonder 128 PCI
                1002 0028  Rage 128 AIW
                1002 0029  Rage 128 AIW
-       5046  Rage 4 [Rage 128 PRO AGP 4X TMDS]
+       5046  Rage 4 [Rage 128 PRO AGP 4X]
                1002 0004  Rage Fury Pro
                1002 0008  Rage Fury Pro/Xpert 2000 Pro
                1002 0014  Rage Fury Pro
                1002 0048  Rage Fury Pro
                1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)
                1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)
-       5050  Rage128 [Xpert 128 PCI]
+       5050  Rage 4 [Rage 128 PRO PCI / Xpert 128 PCI]
                1002 0008  Xpert 128
-       5052  Rage 128 PRO AGP 4X TMDS
+       5052  Rage 4 [Rage 128 PRO AGP 4X]
        5144  R100 [Radeon 7200 / All-In-Wonder Radeon]
                1002 0008  Radeon 7000/Radeon VE
                1002 0009  Radeon 7000/Radeon
        524c  Rage 128 VR AGP
                1002 0008  Xpert 99/Xpert 2000
                1002 0088  Xpert 99
-       5346  Rage 128 SF/4x AGP 2x
-               1002 0048  RAGE 128 16MB VGA TVOUT AMC PAL
        534d  Rage 128 4X AGP 4x
                1002 0008  Xpert 99/Xpert 2000
                1002 0018  Xpert 2000
        554a  R423 [Radeon X800 XT Platinum Edition]
        554b  R423 [Radeon X800 GT/SE]
                1002 0302  Radeon X800 SE
-       554d  R430 [Radeon X800 XL]
+       554d  R480 [Radeon X800 GTO2/XL]
                1002 0322  All-In-Wonder X800 XL
                1458 2124  GV-R80L256V-B (AGP)
        554e  R430 [All-In-Wonder X800 GT]
        5551  R423 GL [FireGL V5100]
        5569  R423 [Radeon X800 PRO] (Secondary)
        556b  R423 [Radeon X800 GT] (Secondary)
-       556d  R430 [Radeon X800 XL] (Secondary)
+       556d  R480 [Radeon X800 GTO2/XL] (Secondary)
                1458 2125  GV-R80L256V-B (AGP)
        556f  R430 [Radeon X800] (Secondary)
        5571  R423 GL [FireGL V5100] (Secondary)
        5957  RX780/RX790 Host Bridge
                1849 5957  A770CrossFire Motherboard
        5958  RD780 Host Bridge
-       5960  RV280 [Radeon 9200 PRO]
+       5960  RV280 [Radeon 9200 PRO / 9250]
                17af 2020  Excalibur Radeon 9250
        5961  RV280 [Radeon 9200]
                1002 2f72  All-in-Wonder 9200 Series
                1642 3c81  Radeon HD 8670
                1642 3c91  Radeon HD 8670
                1642 3f09  Radeon R7 350
-       6611  Oland [Radeon HD 8570 / R7 240/340 / Radeon 520 OEM]
+       6611  Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM]
                1028 210b  Radeon R5 240 OEM
                1642 1869  Radeon 520 OEM
                174b 4248  Radeon R7 240 OEM
        67cc  Ellesmere [Polaris10]
        67cf  Ellesmere [Polaris10]
        67d0  Ellesmere [Radeon Pro V7300X / V7350x2]
+       67d7  Ellesmere [Radeon Pro WX 5100 / Barco MXRT-6700]
        67df  Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]
                1002 0b37  Radeon RX 480
                1028 1722  Radeon RX 570X
                1682 9480  Radeon RX 480
                1682 9588  Radeon RX 580 XTR
                1682 c570  Radeon RX 570
+               1682 c580  Radeon RX 580
                174b e347  Radeon RX 470/480
                174b e349  Radeon RX 470
                1787 a470  Radeon RX 470
        67ef  Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]
                1028 1703  RX 560D OEM OC 2 GB
                103c 3421  Radeon RX 460
+               1043 0561  AREZ Radeon RX 560
                106b 0160  Radeon Pro 460
                106b 0166  Radeon Pro 455
                106b 0167  Radeon Pro 450
        687f  Vega 10 XL/XT [Radeon RX Vega 56/64]
                1002 0b36  RX Vega64
                1002 6b76  RX Vega64
+               1458 230c  Radeon RX VEGA 56 GAMING OC 8G
        6880  Lexington [Radeon HD 6550M]
                103c 163c  Pavilion dv6 Radeon HD 6550M
        6888  Cypress XT [FirePro V8800]
                148c 9380  Radeon R9 380
 # Make naming scheme consistent
                174b e308  Radeon R9 380 Nitro 4G D5
+       693b  Tonga PRO GL [FirePro W7100 / Barco MXRT-7600]
        694c  Polaris 22 XT [Radeon RX Vega M GH]
        694e  Polaris 22 XL [Radeon RX Vega M GL]
        694f  Polaris 22 MGL XL [Radeon Pro WX Vega M GL]
        7100  R520 [Radeon X1800 XT]
        7101  R520/M58 [Mobility Radeon X1800 XT]
        7102  R520/M58 [Mobility Radeon X1800]
-       7104  R520 GL [FireGL V7200]
+       7104  R520 GL [FireGL V7200 / Barco MXTR-5100]
                13cc 3d0a  MXRT-5100
        7109  R520 [Radeon X1800 XL]
                1002 0322  All-in-Wonder X1800XL
        9612  RS780M [Mobility Radeon HD 3200]
        9613  RS780MC [Mobility Radeon HD 3100]
        9614  RS780D [Radeon HD 3300]
+       9615  RS780E [Radeon HD 3200]
        9616  RS780L [Radeon 3000]
        9640  Sumo [Radeon HD 6550D]
        9641  Sumo [Radeon HD 6620G]
        9917  Trinity [Radeon HD 7620G]
        9918  Trinity [Radeon HD 7600G]
        9919  Trinity [Radeon HD 7500G]
-       991e  Bishop
+       991e  Bishop [Xbox One S APU]
        9920  Liverpool [Playstation 4 APU]
        9921  Liverpool HDMI/DP Audio Controller
        9922  Starshp
        1466  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 6
        1467  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 7
        1468  Zeppelin Cryptographic Coprocessor NTBCCP
+       1470  Vega 10 PCIe Bridge
+       1471  Vega 10 PCIe Bridge
        1480  Starship/Matisse Root Complex
                1462 7c37  X570-A PRO motherboard
        1481  Starship/Matisse IOMMU
                105d 0009  Imagine 128 series 2e 4Mb DRAM
                105d 000a  Imagine 128 series 2 8Mb VRAM
                105d 000b  Imagine 128 series 2 8Mb H-VRAM
-               11a4 000a  Barco Metheus 5 Megapixel
-               13cc 0000  Barco Metheus 5 Megapixel
-               13cc 0004  Barco Metheus 5 Megapixel
-               13cc 0005  Barco Metheus 5 Megapixel
-               13cc 0006  Barco Metheus 5 Megapixel
-               13cc 0008  Barco Metheus 5 Megapixel
-               13cc 0009  Barco Metheus 5 Megapixel
-               13cc 000a  Barco Metheus 5 Megapixel
-               13cc 000c  Barco Metheus 5 Megapixel
+               11a4 000a  Metheus 5 Megapixel
+               13cc 0000  Metheus 5 Megapixel
+               13cc 0004  Metheus 5 Megapixel
+               13cc 0005  Metheus 5 Megapixel
+               13cc 0006  Metheus 5 Megapixel
+               13cc 0008  Metheus 5 Megapixel
+               13cc 0009  Metheus 5 Megapixel
+               13cc 000a  Metheus 5 Megapixel
+               13cc 000c  Metheus 5 Megapixel
        493d  Imagine 128 T2R [Ticket to Ride]
-               11a4 000a  Barco Metheus 5 Megapixel, Dual Head
-               11a4 000b  Barco Metheus 5 Megapixel, Dual Head
-               13cc 0002  Barco Metheus 4 Megapixel, Dual Head
-               13cc 0003  Barco Metheus 5 Megapixel, Dual Head
-               13cc 0007  Barco Metheus 5 Megapixel, Dual Head
-               13cc 0008  Barco Metheus 5 Megapixel, Dual Head
-               13cc 0009  Barco Metheus 5 Megapixel, Dual Head
-               13cc 000a  Barco Metheus 5 Megapixel, Dual Head
+               11a4 000a  Metheus 5 Megapixel, Dual Head
+               11a4 000b  Metheus 5 Megapixel, Dual Head
+               13cc 0002  Metheus 4 Megapixel, Dual Head
+               13cc 0003  Metheus 5 Megapixel, Dual Head
+               13cc 0007  Metheus 5 Megapixel, Dual Head
+               13cc 0008  Metheus 5 Megapixel, Dual Head
+               13cc 0009  Metheus 5 Megapixel, Dual Head
+               13cc 000a  Metheus 5 Megapixel, Dual Head
        5348  Revolution 4
                105d 0037  Revolution IV-FP AGP (For SGI 1600SW)
                11a4 0028  PVS5600M
                1682 211c  GeForce 6600 256MB DDR DUAL DVI TV
        00f3  NV43 [GeForce 6200]
        00f4  NV43 [GeForce 6600 LE]
-       00f5  G71 [GeForce 7800 GS]
+       00f5  G71 [GeForce 7800 GS AGP]
        00f6  NV43 [GeForce 6800 GS/XT]
                1682 217e  XFX GeForce 6800 XTreme 256MB DDR3 AGP
        00f8  NV45GL [Quadro FX 3400/4400]
        02a0  NV2A [XGPU]
        02a5  MCPX CPU Bridge
        02a6  MCPX Memory Controller
-       02e0  G73 [GeForce 7600 GT]
+       02e0  G73 [GeForce 7600 GT AGP]
                02e0 2249  GF 7600GT 560M 256MB DDR3 DUAL DVI TV
-       02e1  G73 [GeForce 7600 GS]
+       02e1  G73 [GeForce 7600 GS AGP]
                1682 222b  PV-T73K-UAL3 (256MB)
                1682 2247  GF 7600GS 512MB DDR2
-       02e2  G73 [GeForce 7300 GT]
-       02e3  G71 [GeForce 7900 GS]
-       02e4  G71 [GeForce 7950 GT]
+       02e2  G73 [GeForce 7300 GT AGP]
+       02e3  G71 [GeForce 7900 GS AGP]
+       02e4  G71 [GeForce 7950 GT AGP]
                1682 2271  PV-T71A-YDF7 (512MB)
+       02e5  G71 [GeForce 7600 GS AGP]
        02f0  C51 Host Bridge
                103c 2a34  Pavilion a1677c
                103c 30b7  Presario V6133CL
        1e04  TU102 [GeForce RTX 2080 Ti]
        1e07  TU102 [GeForce RTX 2080 Ti Rev. A]
                1462 3715  RTX 2080 Ti GAMING X TRIO
-       1e2d  TU102B
-       1e2e  TU102B
+       1e2d  TU102 [GeForce RTX 2080 Ti Engineering Sample]
+       1e2e  TU102 [GeForce RTX 2080 Ti 12GB Engineering Sample]
        1e30  TU102GL [Quadro RTX 6000/8000]
                10de 129e  Quadro RTX 8000
                10de 12ba  Quadro RTX 6000
-       1e36  TU102GL
+       1e36  TU102GL [Quadro RTX 6000]
        1e37  TU102GL [GRID RTX T10-4/T10-8/T10-16]
                10de 1347  GRID RTX T10-8
                10de 1348  GRID RTX T10-4
        1f51  TU106BM [GeForce RTX 2060 Mobile]
        1f54  TU106BM [GeForce RTX 2070 Mobile]
        1f55  TU106BM [GeForce RTX 2060 Mobile]
+       1f76  TU106GLM [Quadro RTX 3000 Mobile Refresh]
        1f81  TU117
        1f82  TU117 [GeForce GTX 1650]
        1f91  TU117M [GeForce GTX 1650 Mobile / Max-Q]
        1f95  TU117M [GeForce GTX 1650 Ti Mobile]
        1f96  TU117M [GeForce GTX 1650 Mobile / Max-Q]
        1f97  TU117M [GeForce MX450]
+       1f98  TU117M [GeForce MX450]
        1f99  TU117M
+       1f9c  TU117M [GeForce MX450]
        1fae  TU117GL
        1fb8  TU117GLM [Quadro T2000 Mobile / Max-Q]
        1fb9  TU117GLM [Quadro T1000 Mobile]
        21bf  TU116GL
        21c4  TU116 [GeForce GTX 1660 SUPER]
        21d1  TU116BM [GeForce GTX 1660 Ti Mobile]
+       2204  GA102 [GeForce RTX 3090]
+       2206  GA102 [GeForce RTX 3080 10GB / 20GB]
+               10de 146d  GA102 [GeForce RTX 3080 20GB]
+               1462 3892  RTX 3080 10GB GAMING X TRIO
+       222b  GA102 [GeForce RTX 3090 Engineering Sample]
+       222f  GA102 [GeForce RTX 3080 11GB / 12GB Engineering Sample]
+       2230  GA102GL [RTX A6000]
+       223f  GA102GL
+       2482  GA104 [GeForce RTX 3070 Ti]
+       2484  GA104 [GeForce RTX 3070]
+       2486  GA104 [GeForce RTX 3060 Ti]
+       249c  GA104M [GeForce RTX 3070 Mobile]
+       249d  GA104M [GeForce RTX 3070 Mobile / Max-Q]
+       24af  GA104 [GeForce RTX 3070 Engineering Sample]
+       24bf  GA104 [GeForce RTX 3070 Engineering Sample]
+       252f  GA106 [GeForce RTX 3060 Engineering Sample]
 10df  Emulex Corporation
        0720  OneConnect NIC (Skyhawk)
                103c 1934  FlexFabric 20Gb 2-port 650M Adapter
                17aa b023  ThinkPad E595
        c821  RTL8821CE 802.11ac PCIe Wireless Network Adapter
        c822  RTL8822CE 802.11ac PCIe Wireless Network Adapter
+       c82f  RTL8822CE 802.11ac PCIe Wireless Network Adapter
        d723  RTL8723DE 802.11b/g/n PCIe Adapter
 10ed  Ascii Corporation
        7310  V7310
                117c 00a2  Celerity FC-321E
                117c 00a3  Celerity FC-322E
                117c 00ac  Celerity FC-324E
+       00bb  Celerity FC 32/64Gb/s Gen 7 Fibre Channel HBA
+               117c 00bc  Celerity FC-321P
+               117c 00bd  Celerity FC-322P
+               117c 00be  Celerity FC-324P
+       00e6  ExpressSAS GT 12Gb/s SAS/SATA HBA
+               117c 00c0  ExpressSAS H1280 GT
+               117c 00c1  ExpressSAS H1208 GT
+               117c 00c2  ExpressSAS H1244 GT
+               117c 00c3  ExpressSAS H12F0 GT
+               117c 00c4  ExpressSAS H120F GT
        8013  ExpressPCI UL4D
        8014  ExpressPCI UL4S
        8027  ExpressPCI UL5D
        0314  Model 14 Road Runner Frame Grabber
        0324  Model 24 Road Runner Frame Grabber
        0344  Model 44 Road Runner Frame Grabber
+       b04e  Claxon CXP4 CoaXPress frame grabber
 118e  Hermstedt GmbH
 118f  Green Logic
 1190  Tripace
        0811  SM811 LynxE
        0820  SM820 Lynx3D
        0910  SM910
+       2262  SM2262/SM2262EN SSD Controller
 1270  Olympus Optical Co., Ltd.
 1271  GW Instruments
 1272  Telematics International
 13c9  Eaton Corporation
 13ca  Iomega Corporation
 13cb  Yano Electric Co Ltd
-13cc  Metheus Corporation
+13cc  BARCO
 13cd  Compatible Systems Corporation
 13ce  Cocom A/S
 13cf  Studio Audio & Video Ltd
 144c  Catalina Research Inc
 144d  Samsung Electronics Co Ltd
        1600  Apple PCIe SSD
+       a544  Exynos 8890 PCIe Root Complex
        a800  XP941 PCIe SSD
        a802  NVMe SSD Controller SM951/PM951
        a804  NVMe SSD Controller SM961/PM961
                1028 2097  EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 1.92TB
                1028 2098  EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 3.84TB
                1028 2099  EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 7.68TB
+       ecec  Exynos 8895 PCIe Root Complex
 144e  OLITEC
 144f  Askey Computer Corp.
 1450  Octave Communications Ind.
        16d5  BCM57407 NetXtreme-E 10GBase-T Ethernet Controller
        16d6  BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller
                14e4 4120  NetXtreme E-Series Advanced Dual-port 10Gb SFP+ Ethernet Network Daughter Card
+               14e4 4126  NetXtreme-E Dual-port 10G SFP+ Ethernet OCP 3.0 Adapter (BCM957412N4120C)
                152d 8b20  BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller
                152d 8b22  BCM57412 NetXtreme-E 25Gb RDMA Ethernet Controller
        16d7  BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller
                14e4 1402  BCM957414A4142CC 10Gb/25Gb Ethernet PCIe
                14e4 1404  BCM957414M4142C OCP 2x25G Type1 wRoCE
                14e4 4140  NetXtreme E-Series Advanced Dual-port 25Gb SFP28 Network Daughter Card
+               14e4 4146  NetXtreme-E Dual-port 25G SFP28 Ethernet OCP 3.0 Adapter (BCM957414N4140C)
                1590 020e  Ethernet 25Gb 2-port 631SFP28 Adapter
                1590 0211  Ethernet 25Gb 2-port 631FLR-SFP28 Adapter
        16d8  BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller
                1028 1feb  NetXtreme-E 10Gb SFP+ Adapter
-               14e4 4163  BCM957416M4163C OCP 2x10GBT Type1 wRoCE
+               14e4 4163  NetXtreme-E Dual-port 10GBASE-T Ethernet OCP 2.0 Adapter (BCM957416M4163C)
+               14e4 4166  NetXtreme-E Dual-port 10GBASE-T Ethernet OCP 3.0 Adapter (BCM957416N4160C)
                1590 020c  Ethernet 10Gb 2-port 535T Adapter
                1590 0212  Ethernet 10Gb 2-port 535FLR-T Adapter
        16d9  BCM57417 NetXtreme-E 10GBASE-T RDMA Ethernet Controller
        16e7  BCM57404 NetXtreme-E Ethernet Partition
        16e8  BCM57406 NetXtreme-E Ethernet Partition
        16e9  BCM57407 NetXtreme-E 25Gb Ethernet Controller
+       16eb  BCM57412 NetXtreme-E RDMA Partition
        16ec  BCM57414 NetXtreme-E Ethernet Partition
        16ed  BCM57414 NetXtreme-E RDMA Partition
        16ee  BCM57416 NetXtreme-E Ethernet Partition
                103c 30c0  Compaq 6710b
                17aa 3a23  IdeaPad S10e
        1750  BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet
+               14e4 2100  NetXtreme-E Dual-port 100G QSFP56 Ethernet PCIe4.0 x16 Adapter (BCM957508-P2100G)
+               14e4 5208  NetXtreme-E Dual-port 100G QSFP56 Ethernet OCP 3.0 Adapter (BCM957508-N2100G)
        1751  BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet
        1752  BCM57502 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet
+       1800  BCM57502 NetXtreme-E Ethernet Partition
+       1801  BCM57504 NetXtreme-E Ethernet Partition
+       1802  BCM57508 NetXtreme-E Ethernet Partition
+       1803  BCM57502 NetXtreme-E RDMA Partition
+       1804  BCM57504 NetXtreme-E RDMA Partition
+       1805  BCM57508 NetXtreme-E RDMA Partition
        1806  BCM5750X NetXtreme-E Ethernet Virtual Function
        1807  BCM5750X NetXtreme-E RDMA Virtual Function
        3352  BCM3352
        4410  BCM4413 iLine32 HomePNA 2.0
        4411  BCM4413 V.90 56k modem
        4412  BCM4412 10/100BaseT
+       441f  BCM4361 802.11ac Dual-Band Wireless Network Controller
+       4420  BCM4361 802.11ac 2.4 GHz Wireless Network Controller
+       4421  BCM4361 802.11ac 5 GHz Wireless Network Controller
        4430  BCM44xx CardBus iLine32 HomePNA 2.0
        4432  BCM4432 CardBus 10/100BaseT
        4464  BCM4364 802.11ac Wireless Network Adapter
 1526  ISS, Inc
 1527  SOLECTRON
 1528  ACKSYS
-1529  AMERICAN MICROSystems Inc
+# nee American Microsystems Inc
+1529  ON Semiconductor
 152a  QUICKTURN DESIGN Systems
 152b  FLYTECH Technology CO Ltd
 152c  MACRAIGOR Systems LLC
        1100  PCI Express Core Reference Design
        110f  PCI Express Core Reference Design Virtual Function
        1110  XpressRich Reference Design
+       1111  XpressRich-AXI Ref Design
+       1112  QuickPCIe
        1113  XpressSwitch
+       1114  Inspector
+       1115  XpressLINK Ref Design
+       1116  XpressLINK-SOC Ref Design
        be00  PCI Express Bridge
 1557  MEDIASTAR Co Ltd
 1558  CLEVO/KAPOK Computer
                15b3 0007  Mellanox ConnectX®-5 MCX516A-CCAT
                15b3 0020  ConnectX®-5 EN network interface card, 10/25GbE dual-port SFP28, PCIe3.0 x8, tall bracket ; MCX512A-ACAT
                15b3 0068  ConnectX®-5 EN network interface card for OCP2.0, Type 1, with host management, 25GbE dual-port SFP28, PCIe3.0 x8, no bracket Halogen free ; MCX542B-ACAN
-               15b3 0125  Tencent ConnectX-5 EN Ex network interface card for OCP 3.0, with host management, 50GbE Dual-port QSFP28, PCIe4.0 x16, Thumbscrew (pull-tab) bracket
        1018  MT27800 Family [ConnectX-5 Virtual Function]
        1019  MT28800 Family [ConnectX-5 Ex]
                15b3 0008  ConnectX-5 Ex EN network interface card, 100GbE dual-port QSFP28, PCIe4.0 x16, tall bracket; MCX516A-CDAT
+               15b3 0125  Tencent ConnectX-5 EN Ex network interface card for OCP 3.0, with host management, 50GbE Dual-port QSFP28, PCIe4.0 x16, Thumbscrew (pull-tab) bracket
        101a  MT28800 Family [ConnectX-5 Ex Virtual Function]
        101b  MT28908 Family [ConnectX-6]
        101c  MT28908 Family [ConnectX-6 Virtual Function]
        0041  QCA6164 802.11ac Wireless Network Adapter
        0042  QCA9377 802.11ac Wireless Network Adapter
                11ad 08a6  Qualcomm Atheros QCA9377 802.11ac Wireless Network Adapter
+# compatible with Lenovo's BIOS lock
+               17aa 0901  Qualcomm Atheros QCA9377 Wireless Network Adapter
        0046  QCA9984 802.11ac Wave 2 Wireless Network Adapter
        0050  QCA9887 802.11ac Wireless Network Adapter
        0207  AR5210 Wireless Network Adapter [AR5000 802.11a]
        0142  PCA7208AS - Analog inputs/Outputs
        0143  PCA7408AL - Analog Inputs/Outputs
        0144  PCA7408AS - Analog Inputs/Outputs
+       0145  PCA-7228AL Multifunction PCI IO card
+       0146  PCA-7228AS Multifunction PCI IO card
+       0147  PCA7428AL Multifunction PCI IO card
+       0148  PCA7428AS Multifunction PCI IO card
+       0149  PCA7228EL Multifunction PCI IO card with isolated analog inputs
+       0150  PCA7428EL Multifunction PCI IO card with isolated analog inputs
+       0151  PCA7628AL - PCI card with analog inputs, counters and DIO
+       0152  PCA7628AS PCI card with analog inputs, outputs, counters and DIO
+       0161  PCA7288A PCI card with analog outputs, counters and DIO
+       0180  PCI1052 Communication card for MicroUnit network
        0214  PCT-7424C (F0) PC card with standard counters
        0215  PCT-7424C (F1) PC card with standard counters
        0216  PCT-7424E (F0) PC card with standard counters
        8083  GL880 USB 1.1 UHCI controller
        8084  GL880 USB 2.0 EHCI controller
        9750  GL9750 SD Host Controller
+       e763  GL9763E eMMC Controller
 17aa  Lenovo
        402b  Intel 82599ES 10Gb 2-port Server Adapter X520-2
 17ab  Phillips Components
        0002  AGN300 802.11 a/b/g True MIMO Wireless Card
                1385 6d00  WPNT511 RangeMax 240 Mbps Wireless CardBus Adapter
                1737 0054  WPC54GX4 v1 802.11g Wireless-G Notebook Adapter with SRX400
+       0105  MSM8998 PCIe Root Complex
+       0108  SM8150/SA8195P PCIe Root Complex
+       0300  MDM9x35 LTE Modem
+       0301  MDM9640 PCIe Root Complex
+       0302  MDM9x55 LTE Modem [Snapdragon X12]
        0400  Datacenter Technologies QDF2432 PCI Express Root Port
        0401  Datacenter Technologies QDF2400 PCI Express Root Port
+       1000  QCS405 PCIe Root Complex
 17cc  NetChip Technology, Inc
        2280  USB 2.0
 17cd  Cadence Design Systems, Inc.
        0087  MPC8343
        00b4  MPC8315E
        00b6  MPC8314E
-               1a56 1101  Killer Xeno Pro Gigabit Ethernet Controller
+               1a56 1101  Bigfoot Killer Xeno Pro Gigabit Ethernet Controller
        00c2  MPC8379E
        00c3  MPC8379
        00c4  MPC8378E
        7011  MPC8641D PCI Host Bridge
        7018  MPC8610
        c006  MPC8308
-               1a56 1201  Killer E2100 Gigabit Ethernet Controller
+               1a56 1201  Bigfoot Killer E2100 Gigabit Ethernet Controller
 # PCIe interface for emulator
        fc02  RedStone
 # CFI device over PCIe
 1966  Orad Hi-Tec Systems
        1975  DVG64 family
        1977  DVG128 family
+       1979  3DVG/UHD3
+       1980  HDV2/UHD2
+               1234 3160  UHD2LC
+               1234 3300  Legacy UHD2
+               1234 3410  UHD2
 # nee Atheros Communications, Inc. nee Attansic Technology Corp.
 1969  Qualcomm Atheros
        1026  AR8121/AR8113/AR8114 Gigabit or Fast Ethernet
        0009  CAN interface PCI104 HS/HS
 1a08  Sierra semiconductor
        0000  SC15064
+1a0d  SEAKR Engineering
 1a0e  DekTec Digital Video B.V.
        083f  DTA-2111 VHF/UHF Modulator
 1a17  Force10 Networks, Inc.
        0065  Atomix HDMI STAN
        0070  RED Rocket
        0090  CinePlay
-1a56  Bigfoot Networks, Inc.
+# nee Bigfoot Networks, now owned by Intel
+1a56  Rivet Networks
 1a57  Highly Reliable Systems
 1a58  Razer USA Ltd.
 1a5d  Celoxica
                4254 0552  S952 v3
 1ae0  Google, Inc.
        0042  Compute Engine Virtual Ethernet [gVNIC]
+       abcd  Airbrush Combined Paintbox IPU/Oscar Edge TPU [Pixel Neural Core]
 1ae3  SANBlaze Technology, Inc.
 1ae7  First Wise Media GmbH
        0520  HFC-S PCI A [X-TENSIONS XC-520]
 1ae8  Silicon Software GmbH
-       0a40  microEnable IV-BASE x1
-       0a41  microEnable IV-FULL x1
-       0a44  microEnable IV-FULL x4
-       0e44  microEnable IV-GigE x4
+# CameraLink frame grabber for Visual Applets
+       0751  mE5 marathon VCL
+# CameraLink HS frame grabber
+       0752  mE5 marathon AF2
+# CoaXpress frame grabber
+       0753  mE5 marathon ACX QP
+# CameraLink frame grabber
+       0754  mE5 marathon ACL
+# CoaXpress frame grabber
+       0755  mE5 marathon ACX SP
+# CoaXpress frame grabber
+       0756  mE5 marathon ACX DP
+# CoaXpress frame grabber for Visual Applets
+       0757  mE5 marathon VCX QP
+# CameraLink HS frame grabber for Visual Applets
+       0758  mE5 marathon VF2
+# CameraLink frame grabber for Visual Applets / AI applications
+       0759  mE5 marathon VCLx
+# CameraLink frame grabber
+       0a40  microEnable IV AD1-CL
+# CameraLink frame grabber for Visual Applets
+       0a41  microEnable IV VD1-CL
+# CameraLink frame grabber
+       0a42  microEnable IV AD4-CL
+# CameraLink frame grabber for Visual Applets
+       0a44  microEnable IV VD4-CL
+# CameraLink frame grabber
+       0a45  microEnable IV AS1-CL
+# CoaXpress frame grabber
+       0a53  microEnable 5 AQ8-CXP6B
+# CoaXpress frame grabber for Visual Applets
+       0a54  microEnable 5 VQ8-CXP6B
+# CoaXpress frame grabber for Visual Applets
+       0a56  microEnable 5 VQ8-CXP6D
+# CoaXpress frame grabber
+       0a57  microEnable 5 AQ8-CXP6D
+# CameraLink frame grabber for Visual Applets
+       0a58  microEnable 5 VD8-CL
+# CameraLink frame grabber
+       0a5a  microEnable 5 AD8-CL
+# OEM product
+       0b52  mE5 Abacus 4G Base
+# OEM product
+       0b53  mE5 Abacus 4G Base II
+# OEM product
+       0b61  mE6 Abacus 4TG
+# CoaXpress frame grabber
+       0b63  CXP-12 Interface Card 1C
+# GigE Vision frame grabber
+       0e42  microEnable IV AQ4-GE
+# GigE Vision frame grabber for Visual Applets
+       0e44  microEnable IV VQ4-GE
 1ae9  Wilocity Ltd.
        0101  Wil6200 PCI Express Upstream Port
        0200  Wil6200 PCI Express Port
        0612  ASM1062 Serial ATA Controller
                1849 0612  Motherboard
        1042  ASM1042 SuperSpeed USB Host Controller
+               1043 1059  K53SM motherboard
                1043 8488  P8B WS Motherboard
                1849 1042  Motherboard
        1080  ASM1083/1085 PCIe to PCI Bridge
        1242  ASM1142 USB 3.1 Host Controller
        1343  ASM1143 USB 3.1 Host Controller
        2142  ASM2142 USB 3.1 Host Controller
+       3242  ASM3242 USB 3.2 Host Controller
 1b26  Netcope Technologies, a.s.
        c132  COMBO-LXT155
        c1c0  NFB-100G1-e0
        0602  NumaChip N602
 1b4b  Marvell Technology Group Ltd.
        0640  88SE9128 SATA III 6Gb/s RAID Controller
+       2241  88NR2241 Non-Volatile memory controller
+               1d49 0306  ThinkSystem M.2 NVMe 2-Bay RAID Enablement Kit
+               1d49 0307  ThinkSystem 7mm NVMe 2-Bay Rear RAID Enablement Kit
        9120  88SE9120 SATA 6Gb/s Controller
        9123  88SE9123 PCIe SATA 6.0 Gb/s controller
                dc93 600e  DC-6xxe series SATA 6G controller
                1028 1fe2  BOSS-S1 Adapter
                1028 2010  BOSS-S2 Adapter
                1d49 0300  ThinkSystem M.2 with Mirroring Enablement Kit
+               1d49 0301  ThinkSystem SR630 x16 PCIE with 4 SATA ports Riser
+               1d49 0302  ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit
+               1d49 0303  ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit
+               1d49 0304  ThinkSystem M.2 SATA 2-Bay RAID Enablement Kit
+               1d49 0305  ThinkSystem 7mm SATA 2-Bay Rear RAID Enablement Kit
        9235  88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller
        9445  88SE9445 PCIe 2.0 x4 4-Port SAS/SATA 6 Gbps RAID Controller
        9480  88SE9480 SAS/SATA 6Gb/s RAID controller
        9485  88SE9485 SAS/SATA 6Gb/s controller
+1b4c  GALAX
 1b55  NetUP Inc.
        18f6  Dual DVB Universal CI card
        18f7  Dual DVB Universal CI card rev 1.4
        1285  PC300 NVMe Solid State Drive 1TB
        1327  BC501 NVMe Solid State Drive 512GB
        1504  SC300 512GB M.2 2280 SATA Solid State Drive
+       2839  PE8000 Series NVMe Solid State Drive
+               0100 1c5c  PE8000 Series NVMe Solid State Drive
 1c5f  Beijing Memblaze Technology Co. Ltd.
        000d  PBlaze5 520/526 AIC
        003d  PBlaze5 920/926 AIC
 1c8c  Mobiveil, Inc.
 1cb0  Shannon Systems
        d000  Venice NVMe SSD
-               1cb0 2f10  Venice-E Series U.2 SSD
-               1cb0 2f11  Venice Series U.2 SSD
-               1cb0 2f12  Venice-X Series U.2 SSD
-               1cb0 af10  Venice-E Series AIC SSD
-               1cb0 af11  Venice Series AIC SSD
-               1cb0 af12  Venice-X Series AIC SSD
+               1cb0 2010  Venice-E Series OCS U.2
+               1cb0 2011  Venice Series OCS U.2
+               1cb0 2012  Venice-X Series OCS U.2
+# Venice-E Series NVMe U.2 SSD(1.92T/3.84T/7.68T)
+               1cb0 2f10  Venice-E Series NVMe U.2
+# Venice Series NVMe U.2 SSD(2T/4T/8T)
+               1cb0 2f11  Venice Series NVMe U.2
+# Venice-X Series NVMe U.2 SSD(1.6T/3.2T/6.4T)
+               1cb0 2f12  Venice-X Series NVMe U.2
+               1cb0 a010  Venice-E Series OCS AIC
+               1cb0 a012  Venice-X Series OCS AIC
+# Venice-E Series NVMe AIC SSD(1.92T/3.84T/7.68T)
+               1cb0 af10  Venice-E Series NVMe AIC
+# Venice-X Series NVMe AIC SSD(1.6T/3.2T/6.4T)
+               1cb0 af12  Venice-X Series NVMe AIC
 1cb1  Collion UG & Co.KG
 1cb5  Focusrite Audio Engineering Ltd
        0002  Clarett
 1d72  Xiaomi
 1d78  DERA Storage
        1512  TAI NVMe Controller
-               1d78 2003  D5457 HHHL 1.6TB NVMe SSD
                1d78 2004  D5437 HHHL 2TB NVMe SSD
-               1d78 2005  D5457 HHHL 3.2TB NVMe SSD
                1d78 2006  D5437 HHHL 4TB NVMe SSD
-               1d78 2007  D5457 HHHL 6.4TB NVMe SSD
                1d78 2008  D5437 HHHL 8TB NVMe SSD
-               1d78 2103  D5457 U.2 1.6TB NVMe SSD
                1d78 2104  D5437 U.2 2TB NVMe SSD
-               1d78 2105  D5457 U.2 3.2TB NVMe SSD
                1d78 2106  D5437 U.2 4TB NVMe SSD
-               1d78 2107  D5457 U.2 6.4TB NVMe SSD
                1d78 2108  D5437 U.2 8TB NVMe SSD
+               1d78 3003  D5457 HHHL 1.6TB NVMe SSD
+               1d78 3005  D5457 HHHL 3.2TB NVMe SSD
+               1d78 3007  D5457 HHHL 6.4TB NVMe SSD
+               1d78 3103  D5457 U.2 1.6TB NVMe SSD
+               1d78 3105  D5457 U.2 3.2TB NVMe SSD
+               1d78 3107  D5457 U.2 6.4TB NVMe SSD
 1d7c  Aerotech, Inc.
 1d82  NETINT Technologies Inc.
        0101  Codensity D400 SSD
        0401  StarDragon4800 PCI Express Root Port
 1dc5  FADU Inc.
 1dcd  Liqid Inc.
-1dd8  Pensando Systems Inc
+1dd8  Pensando Systems
        1000  DSC Capri Upstream Port
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
        1001  DSC Virtual Downstream Port
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
        1002  DSC Ethernet Controller
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
        1003  DSC Ethernet Controller VF
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
        1004  DSC Management Controller
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
        1007  DSC Storage Accelerator
                1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB
                1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB
                1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB
+               1dd8 4007  DSP DSC-25 10/25G 2p OCP Card
                1dd8 4008  DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC
+               1dd8 400a  DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card
+               1dd8 400c  DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card
+               1dd8 400d  DSP DSC-100 100G 2p QSFP28 Card
 1de0  Groq
        0000  Q100 Tensor Streaming Processor
 1de1  Tekram Technology Co.,Ltd.
 1de5  Eideticom, Inc
        1000  IO Memory Controller
        2000  NoLoad Hardware Development Kit
+       3000  eBPF-based PCIe Accelerator
 1dee  Biwin Storage Technology Co., Ltd.
 1def  Ampere Computing, LLC
        e005  eMAG PCI Express Root Port 0
        0204  ACE-NIC-NID Programmable Network Accelerator
                1df3 0001  ENA1020Z
                1df3 0002  ENA1020ZS
+       0205  ACE-NIC250 Programmable Network Accelerator
+               1df3 0000  Maintenance Mode
+               1df3 0001  ENA2250F
+       0206  ACE-NIC200 Programmable Network Accelerator
+               1df3 0000  Maintenance Mode
+               1df3 0001  ENA2200F
 1df7  opencpi.org
        0001  ml605
        0002  alst4
        1181  TDM 8 Port E1/T1/J1 Adapter
 1e0f  KIOXIA Corporation
        0007  NVMe SSD Controller Cx6
+               1028 2078  DC NVMe CD6 RI 960GB
+               1028 2079  DC NVMe CD6 RI 1.92TB
+               1028 207a  DC NVMe CD6 RI 3.84TB
+               1028 207b  DC NVMe CD6 RI 7.68TB
+               1028 207c  DC NVMe CD6 RI 15.36TB
+               1028 207e  Dell Ent NVMe CM6 RI 1.92TB
+               1028 207f  Dell Ent NVMe CM6 RI 3.84TB
+               1028 2080  Dell Ent NVMe CM6 RI 7.68TB
+               1028 2081  Dell Ent NVMe CM6 RI 15.36TB
+               1028 2084  Dell Ent NVMe CM6 MU 1.6TB
+               1028 2085  Dell Ent NVMe CM6 MU 3.2TB
+               1028 2086  Dell Ent NVMe CM6 MU 6.4TB
+               1028 210a  Dell Ent NVMe FIPS CM6 RI 1.92TB
+               1028 210b  Dell Ent NVMe FIPS CM6 RI 3.84TB
+               1028 210c  Dell Ent NVMe FIPS CM6 RI 7.68TB
+               1028 210d  Dell Ent NVMe FIPS CM6 RI15.36TB
+               1028 210e  Dell Ent NVMe FIPS CM6 MU 1.6TB
+               1028 210f  Dell Ent NVMe FIPS CM6 MU 3.2TB
+               1028 2110  Dell Ent NVMe FIPS CM6 MU 6.4TB
+               1e0f 0001  Generic NVMe CM6 RI 3.84TB
 1e17  Arnold & Richter Cine Technik GmbH & Co. Betriebs KG
 1e24  Squirrels Research Labs
        0101  Acorn CLE-101
        0001  T10 [CloudBlazer]
 # nee Thinci, Inc
 1e38  Blaize, Inc
+       0102  Xplorer X1600
 1e3d  Burlywood, Inc
 1e49  Yangtze Memory Technologies Co.,Ltd
 1e4b  MAXIO Technology (Hangzhou) Ltd.
        0100  The device has already been deleted.
                0000 0100  PY8800 64GB Accelerator
 1e6b  Axiado Corp.
+1e7c  Brainchip Inc
+       bca1  AKD1000 Neural Network Coprocessor [Akida]
 1e85  Heitec AG
 1e89  ID Quantique SA
        0002  Quantis-PCIe-40M
 # aka SED Systems
 1e94  Calian SED
 1e95  Solid State Storage Technology Corporation
+1eb1  VeriSilicon Inc
+       1001  Video Accelerator
 # nee Tumsan Oy
 1fc0  Ascom (Finland) Oy
        0300  E2200 Dual E1/Rawpipe Card
 2348  Racore
        2010  8142 100VG/AnyLAN
 2646  Kingston Technology Company, Inc.
+       2263  A2000, M.2, 500GB
 270b  Xantel Corporation
 270f  Chaintech Computer Co. Ltd
 2711  AVID Technology Inc.
 3442  Bihl+Wiedemann GmbH
        1783  AS-i 3.0 cPCI Master
        1922  AS-i 3.0 PCI Master
-3475  Arastra Inc.
+3475  Arista Networks, Inc.
 3513  ARCOM Control Systems Ltd
 37d9  ITD Firm ltd.
        1138  SCHD-PH-8 Phase detector
        0100  Permedia II 2D+3D
        07a1  Wildcat III 6210
        07a2  Sun XVR-500 Graphics Accelerator
+               3d3d 1047  Sun XVR-600 Graphics Accelerator
        07a3  Wildcat IV 7210
        1004  Permedia
        3d04  Permedia
                1043 844d  P8B WS Motherboard
        0172  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller
        0176  3rd Gen Core processor Graphics Controller
+       0284  Comet Lake PCH-LP LPC Premium Controller/eSPI Controller
+       02a3  Comet Lake PCH-LP SMBus Host Controller
        02a4  Comet Lake SPI (flash) Controller
        02a6  Comet Lake North Peak
+       02c8  Comet Lake PCH-LP cAVS
        02d3  Comet Lake SATA AHCI Controller
        02e0  Comet Lake Management Engine Interface
        02e8  Serial IO I2C Host Controller
        02e9  Comet Lake Serial IO I2C Host Controller
-       02f0  Wireless-AC 9462
-               8086 0070  Intel(R) Wi-Fi 6 AX201 160MHz
+       02ed  Comet Lake PCH-LP USB 3.1 xHCI Host Controller
+       02ef  Comet Lake PCH-LP Shared SRAM
+       02f0  Comet Lake PCH-LP CNVi WiFi
+               8086 0034  Wireless-AC 9560 160MHz
+               8086 0070  Wi-Fi 6 AX201 160MHz
+               8086 0074  Wi-Fi 6 AX201 160MHz
+       02f5  Comet Lake PCH-LP SCS3
        02f9  Comet Lake Thermal Subsytem
        02fc  Comet Lake Integrated Sensor Solution
        0309  80303 I/O Processor PCI-to-PCI Bridge
        0406  Haswell Integrated Graphics Controller
        040a  Xeon E3-1200 v3 Processor Integrated Graphics Controller
        0412  Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller
+               103c 1998  EliteDesk 800 G1
                17aa 309f  ThinkCentre M83
        0416  4th Gen Core Processor Integrated Graphics Controller
                17aa 220e  ThinkPad T440p
        06eb  Comet Lake PCH Serial IO I2C Controller #3
        06ed  Comet Lake USB 3.1 xHCI Host Controller
        06ef  Comet Lake PCH Shared SRAM
-       06f0  Wi-Fi 6 AX201
+       06f0  Comet Lake PCH CNVi WiFi
+               8086 0034  Wireless-AC 9560
+               8086 0074  Wi-Fi 6 AX201 160MHz
+               8086 02a4  Wireless-AC 9462
        06f9  Comet Lake PCH Thermal Controller
        06fb  Comet Lake PCH Serial IO SPI Controller #2
        0700  CE Media Processor A/V Bridge
                1d49 4714  Thinksystem Intel P4600 NVMe AIC
                1d49 4802  Thinksystem U.2 P4510 NVMe SSD
                1d49 4812  Thinksystem U.2 P4610 NVMe SSD
-               8086 4308  Intel SSD D5-P4320 and D5-P4326
+               8086 4308  SSD D5-P4320 and D5-P4326
                8086 4702  NVMe Datacenter SSD [3DNAND] SE 2.5" U.2 (P4500)
                8086 4704  NVMe Datacenter SSD [3DNAND] SE AIC (P4500)
                8086 4712  NVMe Datacenter SSD [3DNAND] ME 2.5" U.2 (P4600)
        0bf6  Atom Processor D2xxx/N2xxx DRAM Controller
        0bf7  Atom Processor D2xxx/N2xxx DRAM Controller
        0c00  4th Gen Core Processor DRAM Controller
+               103c 1998  EliteDesk 800 G1
                17aa 309f  ThinkCentre M83
        0c01  Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller
        0c04  Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller
        0c08  Xeon E3-1200 v3 Processor DRAM Controller
        0c09  Xeon E3-1200 v3/4th Gen Core Processor PCI Express x4 Controller
        0c0c  Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        0c46  Atom Processor S1200 PCI Express Root Port 1
        1539  I211 Gigabit Network Connection
        153a  Ethernet Connection I217-LM
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        153b  Ethernet Connection I217-V
                8086 0009  Ethernet Network Adapter E810-C-Q1
                8086 000a  Ethernet Network Adapter E810-C-Q1 for OCP
                8086 000b  Ethernet 100G 2P E810-C Adapter
+               8086 000c  Ethernet 100G 2P E810-C OCP
        1593  Ethernet Controller E810-C for SFP
                1137 02c3  E810XXVDA4 4x25/10 GbE SFP28 PCIe NIC
                8086 0002  Ethernet Network Adapter E810-L-2
        15d3  JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016]
        15d4  JHL6540 Thunderbolt 3 USB Controller (C step) [Alpine Ridge 4C 2016]
        15d5  Ethernet SDI Adapter FM10420-25GbE-DA2
-               8086 0001  Intel(R) Ethernet SDI Adapter FM10420-25GbE-DA2
+               8086 0001  Ethernet SDI Adapter FM10420-25GbE-DA2
        15d6  Ethernet Connection (5) I219-V
        15d7  Ethernet Connection (4) I219-LM
        15d8  Ethernet Connection (4) I219-V
        15ec  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 4C 2018]
        15ef  JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018]
        15f0  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge DD 2018]
-       15f2  Intel(R) Ethernet Controller I225-LM
-       15f3  Intel(R) Ethernet Controller I225-V
+       15f2  Ethernet Controller I225-LM
+               8086 0001  Ethernet Network Adapter I225-T1
+               8086 0002  Ethernet Network Adapter I225-T1
+       15f3  Ethernet Controller I225-V
        15f4  Ethernet Connection (15) I219-LM
        15f5  Ethernet Connection (15) I219-V
        15f6  I210 Gigabit Ethernet Connection
        18a0  C4xxx Series QAT
        18a1  C4XXX Series QAT Virtual Function
        1900  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
-       1901  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x16)
+       1901  6th-9th Gen Core Processor PCIe Controller (x16)
        1902  HD Graphics 510
        1903  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem
                1028 06d6  Latitude 7275 tablet
                1775 11cc  CC11/CL11
        27e2  82801GR/GH/GHM (ICH7 Family) PCI Express Port 6
                1775 11cc  CC11/CL11
-       280b  Intel(R) Display Audio
        2810  82801HB/HR (ICH8/R) LPC Interface Controller
                1043 81ec  P5B
        2811  82801HEM (ICH8M-E) LPC Interface Controller
        2ffc  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers
        2ffd  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers
        2ffe  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers
+       3140  Easel/Monette Hill Image Processor [Pixel Visual Core]
        3165  Wireless 3165
 # Stone Peak 1x1
                8086 4010  Dual Band Wireless AC 3165
        3185  UHD Graphics 605
        318c  Celeron/Pentium Silver Processor Dynamic Platform and Thermal Framework Processor Participant
        318e  Celeron/Pentium Silver Processor NorthPeak
+       3190  Celeron/Pentium Silver Processor Gaussian Mixture Model
        3192  Gemini Lake P2SB
        3197  Celeron/Pentium Silver Processor PCI-default ISA-bridge
        3198  Celeron/Pentium Silver Processor High Definition Audio
        31d9  Gemini Lake PCI Express Root Port
        31da  Gemini Lake PCI Express Root Port
        31db  Gemini Lake PCI Express Root Port
+       31dc  AC 1550i Wireless
        31ee  Celeron/Pentium Silver Processor Serial IO UART Host Controller
        31f0  Gemini Lake Host Bridge
        3200  GD31244 PCI-X SATA HBA
        372c  Xeon C5500/C3500 Reserved
        373f  Xeon C5500/C3500 IOxAPIC
        37c8  C62x Chipset QuickAssist Technology
+               8086 0001  QuickAssist Adapter 8960
+               8086 0002  QuickAssist Adapter 8970
        37cc  Ethernet Connection X722
        37cd  Ethernet Virtual Function 700 Series
        37ce  Ethernet Connection X722 for 10GbE backplane
        3e18  8th Gen Core 4-core Workstation Processor Host Bridge/DRAM Registers [Coffee Lake S]
        3e1f  8th Gen Core 4-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
                1458 5000  Z370 AORUS Gaming K3-CF
-       3e30  8th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
+       3e30  8th/9th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
        3e33  8th/9th Gen Core Processor Host Bridge/DRAM Registers [Coffee Lake]
        3e34  Coffee Lake HOST and DRAM Controller
        3e81  8th Gen Core Processor PCIe Controller (x16)
        8a1f  Ice Lake Thunderbolt 3 PCI Express Root Port #1
        8a21  Ice Lake Thunderbolt 3 PCI Express Root Port #2
        8a23  Ice Lake Thunderbolt 3 PCI Express Root Port #3
-       8a51  Intel Iris Plus Graphics G7 (Ice Lake)
+       8a51  Iris Plus Graphics G7 (Ice Lake)
        8a52  Iris Plus Graphics G7
        8a56  Iris Plus Graphics G1 (Ice Lake)
        8a5a  Iris Plus Graphics G4 (Ice Lake)
-       8a5c  Intel Iris Plus Graphics G4 (Ice Lake)
+       8a5c  Iris Plus Graphics G4 (Ice Lake)
        8c00  8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode]
        8c01  8 Series Chipset Family 4-port SATA Controller 1 [IDE mode] - Mobile
        8c02  8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]
+               103c 1998  EliteDesk 800 G1
                17aa 309f  ThinkCentre M83
        8c03  8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]
                103c 1909  ZBook 15
        8c0e  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]
        8c0f  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]
        8c10  8 Series/C220 Series Chipset Family PCI Express Root Port #1
+               103c 1998  EliteDesk 800 G1
                1043 8534  ASUS H81I-PLUS
                17aa 220e  ThinkPad T440p
        8c11  8 Series/C220 Series Chipset Family PCI Express Root Port #1
        8c12  8 Series/C220 Series Chipset Family PCI Express Root Port #2
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
        8c13  8 Series/C220 Series Chipset Family PCI Express Root Port #2
        8c14  8 Series/C220 Series Chipset Family PCI Express Root Port #3
        8c1f  8 Series/C220 Series Chipset Family PCI Express Root Port #8
        8c20  8 Series/C220 Series Chipset High Definition Audio Controller
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        8c21  8 Series/C220 Series Chipset High Definition Audio Controller
        8c22  8 Series/C220 Series Chipset Family SMBus Controller
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        8c23  8 Series Chipset Family CHAP Counters
        8c24  8 Series Chipset Family Thermal Management Controller
        8c26  8 Series/C220 Series Chipset Family USB EHCI #1
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 2210  ThinkPad T540p
                17aa 309f  ThinkCentre M83
                2210 17aa  ThinkPad T540p
        8c2d  8 Series/C220 Series Chipset Family USB EHCI #2
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        8c31  8 Series/C220 Series Chipset Family USB xHCI
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        8c33  8 Series/C220 Series Chipset Family LAN Controller
        8c34  8 Series/C220 Series Chipset Family NAND Controller
        8c3a  8 Series/C220 Series Chipset Family MEI Controller #1
                103c 1909  ZBook 15
+               103c 1998  EliteDesk 800 G1
                17aa 220e  ThinkPad T440p
                17aa 309f  ThinkCentre M83
        8c3b  8 Series/C220 Series Chipset Family MEI Controller #2
        8c3c  8 Series/C220 Series Chipset Family IDE-r Controller
        8c3d  8 Series/C220 Series Chipset Family KT Controller
+               103c 1998  EliteDesk 800 G1
        8c40  8 Series/C220 Series Chipset Family LPC Controller
        8c41  8 Series Chipset Family Mobile Super SKU LPC Controller
        8c42  8 Series/C220 Series Chipset Family Desktop Super SKU LPC Controller
                17aa 309f  ThinkCentre M83
        8c4d  8 Series/C220 Series Chipset Family LPC Controller
        8c4e  Q87 Express LPC Controller
+               103c 1998  EliteDesk 800 G1
        8c4f  QM87 Express LPC Controller
                103c 1909  ZBook 15
                17aa 220e  ThinkPad T440p
        9b41  UHD Graphics
        9b44  10th Gen Core Processor Host Bridge/DRAM Registers
        9b54  10th Gen Core Processor Host Bridge/DRAM Registers
+       9b61  Comet Lake-U v1 4c Host Bridge/DRAM Controller
        9b64  10th Gen Core Processor Host Bridge/DRAM Registers
        9bc4  UHD Graphics
+       9bc8  UHD Graphics 630
        9c00  8 Series SATA Controller 1 [IDE mode]
        9c01  8 Series SATA Controller 1 [IDE mode]
        9c02  8 Series SATA Controller 1 [AHCI mode]
                1a56 1552  Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)
        a379  Cannon Lake PCH Thermal Controller
                1028 0869  Vostro 3470
+       a382  400 Series Chipset Family SATA AHCI Controller
+       a3a3  Comet Lake PCH-V SMBus Host Controller
+       a3b1  Comet Lake PCH-V Thermal Subsystem
        a620  6400/6402 Advanced Memory Buffer (AMB)
        abc0  Omni-Path Fabric Switch Silicon 100 Series
        b152  21152 PCI-to-PCI Bridge
        d158  Core Processor Miscellaneous Registers
        f1a5  SSD 600P Series
        f1a6  SSD Pro 7600p/760p/E 6100p Series
-               8086 390b  Intel Corporation SSD Pro 7600p/760p/E 6100p Series [NVM Express]
+               8086 390b  SSD Pro 7600p/760p/E 6100p Series [NVM Express]
        f1a8  SSD 660P Series
 8088  Beijing Wangxun Technology Co., Ltd.
        0101  WX1860A2 Gigabit Ethernet Controller
                9005 0552  Series 8 - ASR-8805 - 8 internal 0 external 12G SAS Port/PCIe 3.0
                9005 0553  Series 8 - ASR-8085 - 0 internal 8 external 12G SAS Port/PCIe 3.0
                9005 0554  Series 8 - ASR-8885 - 8 internal 8 external 12G SAS Port/PCIe 3.0
-       028f  Smart Storage PQI 12G SAS/PCIe 3
+       028f  Smart Storage PQI SAS
                103c 0600  Smart Array P408i-p SR Gen10
                103c 0601  Smart Array P408e-p SR Gen10
                103c 0602  Smart Array P408i-a SR Gen10
@@ -32737,6 +32993,7 @@ ffff  Illegal Vendor ID
 C 00  Unclassified device
        00  Non-VGA unclassified device
        01  VGA compatible unclassified device
+       05  Image coprocessor
 C 01  Mass storage controller
        00  SCSI storage controller
        01  IDE interface
index faaa308b95031515c0471d071a265cbbac6dd9dc..a62adc33e6400f0a6fba474368bfa2e501e654da 100644 (file)
  <tr class="even"><td>Torus Systems Ltd</td><td>TRS</td><td>11/29/1996</td> </tr>
  <tr class="odd"><td>Toshiba America Info Systems Inc</td><td>TAI</td><td>11/29/1996</td> </tr>
  <tr class="even"><td>Toshiba America Info Systems Inc</td><td>TSB</td><td>11/29/1996</td> </tr>
- <tr class="odd"><td>Toshiba Corporation</td><td>TOS</td><td>11/29/1996</td> </tr>
+ <tr class="odd"><td>Dynabook Inc.</td><td>TOS</td><td>11/29/1996</td> </tr>
  <tr class="even"><td>Toshiba Corporation</td><td>TTP</td><td>07/07/2015</td> </tr>
  <tr class="odd"><td>Toshiba Global Commerce Solutions, Inc.</td><td>TGC</td><td>06/26/2012</td> </tr>
  <tr class="even"><td>Toshiba Matsushita Display Technology Co., Ltd</td><td>LCD</td><td>05/24/2000</td> </tr>
  <tr class="even"><td>TECNART CO.,LTD.</td><td>PIS</td><td>10/22/2019</td> </tr>
  <tr class="odd"><td>Moxa Inc.</td><td>MHQ</td><td>10/22/2019</td> </tr>
  <tr class="even"><td>Disguise Technologies</td><td>DSG</td><td>10/22/2019</td> </tr>
+ <tr class="odd"><td>Comark LLC</td><td>CMK</td><td>07/15/2020</td> </tr>
+ <tr class="even"><td>Megapixel Visual Realty</td><td>MPV</td><td>07/15/2020</td> </tr>
+ <tr class="odd"><td>Skyworth</td><td>SKW</td><td>07/15/2020</td> </tr>
+ <tr class="even"><td>Meta View, Inc.</td><td>CFR</td><td>07/15/2020</td> </tr>
+ <tr class="odd"><td>MILCOTS</td><td>MLC</td><td>07/15/2020</td> </tr>
+ <tr class="even"><td>NZXT (PNP same EDID)_</td><td>NXT</td><td>07/15/2020</td> </tr>
       </tbody>
     </table>
   </body>
index ea9dafc0eb97533e343b715e18f2c295179ccc28..02e2ef420927e14fd55a24b090bd010d04b95a86 100644 (file)
@@ -9,8 +9,8 @@
 #      The latest version can be obtained from
 #              http://www.linux-usb.org/usb.ids
 #
-# Version: 2020.07.06
-# Date:    2020-07-06 20:34:08
+# Version: 2020.08.26
+# Date:    2020-08-26 20:34:09
 #
 
 # Vendors, devices and interfaces. Please keep sorted.
        3111  OfficeJet 4100 series
        3117  EWS 2605dtn
        311d  Atheros AR9285 Malbec Bluetooth Adapter
+       312a  LaserJet Pro M701n
        3202  PhotoSmart 1215
        3207  4 GB flash drive
        3211  OfficeJet 4105 series
        3220  Sound Blaster Tactic(3D) Sigma sound card
        3232  Sound Blaster Premium HD [SBX]
        3237  SB X-Fi Surround 5.1 Pro
+       3263  SB X-Fi Surround 5.1 Pro
        3f00  E-Mu Xboard 25 MIDI Controller
        3f02  E-Mu 0202
        3f04  E-Mu 0404
        c22d  G510 Gaming Keyboard
        c22e  G510 Gaming Keyboard onboard audio
        c231  G13 Virtual Mouse
+       c232  Gaming Virtual Keyboard
        c245  G400 Optical Mouse
        c246  Gaming Mouse G300
        c247  G100S Optical Gaming Mouse
        c008  Audio 655 DSP
        c00e  Blackwire C310 headset
        c03b  HD1
+       da60  DA60
 0480  Toshiba America Inc
        0001  InTouch Module
        0004  InTouch Module
 048d  Integrated Technology Express, Inc.
        1165  IT1165 Flash Controller
        1172  Flash Drive
-       1234  Mass storage
+       1234  Chipsbank CBM2199 Flash Drive
        1336  SD/MMC Cardreader
        1345  Multi Cardreader
        8297  IT8297 RGB LED Controller
        a050  Chatman V1
        a052  USB-zyTemp
        a055  Keyboard
+       a075  Optical Gaming Mouse
        a096  Keyboard
        a09f  E-Signal LUOM G10 Mechanical Gaming Mouse
        a100  Mouse [HV-MS735]
        685c  GT-I9250 Phone [Galaxy Nexus] (Mass storage mode)
        685d  GT-I9100 Phone [Galaxy S II] (Download mode)
        685e  GT-I9100 / GT-C3350 Phones (USB Debugging mode)
-       6860  Galaxy series, misc. (MTP mode)
+       6860  Galaxy A5 (MTP)
        6863  Galaxy series, misc. (tethering mode)
        6864  GT-I9070 (network tethering, USB debugging enabled)
        6865  Galaxy (PTP mode)
        1080  NET1080 USB-USB Bridge
        1200  SSDC Adapter II
        1265  File-backed Storage Gadget
-       3424  Lumidigm Venus fingerprint sensor
+       3424  V30x/V4xx fingerprint sensor [Lumidigm]
        a0f0  Cambridge Electronic Devices Power1401 mk 2
        a140  USB Clik! 40
        a141  (OME) PocketZip 40 MP3 Player Driver
        a4a2  Linux-USB Ethernet/RNDIS Gadget
        a4a3  Linux-USB user-mode isochronous source/sink
        a4a4  Linux-USB user-mode bulk source/sink
-       a4a5  Pocketbook Pro 903 / Mobius 2 Action Cam / xDuoo X3
+       a4a5  Pocketbook Pro 903 / Mobius 2 Action Cam / xDuoo X3 / PocketBook Pro 602
        a4a6  Linux-USB Serial Gadget
        a4a7  Linux-USB Serial Gadget (CDC ACM mode)
        a4a8  Linux-USB Printer Gadget
        035b  Walkman NWZ-A828
        035c  NWZ-A726/A728/A729
        035f  UP-DR200 Photo Printer
+       0360  M2 Card Reader
        0382  Memory Stick PRO-HG Duo Adaptor (MSAC-UAH1)
        0385  Walkman NWZ-E436F
        0387  IC Recorder (P)
        106d  Porsche Design Mobile Drive
        106e  Porsche Design Desktop Drive
        1094  Rugged THB
+       1095  Rugged
        a601  HardDrive
        a602  CD R/W
 05a0  Vetronix Corp.
        4001  Bluetooth Headset in DFU mode
        4002  Bluetooth Headset Series 2
        4003  Bluetooth Headset Series 2 in DFU mode
+       400d  SoundLink Color II speaker in DFU mode
+       40fe  SoundLink Color II speaker
        bc50  SoundLink Wireless Mobile speaker
        bc51  SoundLink Wireless Mobile speaker in DFU mode
 05a8  Spacetec IMC Corp.
        0361  SunplusIT INC. HP Truevision HD Webcam
        036e  Webcam
        0374  HP EliteBook integrated HD Webcam
+       038e  HP Wide Vision HD integrated webcam
        03a1  XiaoMi Webcam
        03b1  Webcam
        03bc  HP Wide Vision HD Integrated Webcam
        0610  Onext EG210U MODEM
        0611  AlDiga AL-11U Quad-band GSM/GPRS/EDGE modem
        1231  Orico SATA External Hard Disk Drive Lay-Flat Docking Station with USB 3.0 & eSATA interfaces.
-       2303  PL2303 Serial Port
+       2303  PL2303 Serial Port / Mobile Action MA-8910P
        2305  PL2305 Parallel Port
        2306  Raylink Bridge Controller
        2307  PL2307 USB-ATAPI4 Bridge
        01c9  OKI B430 Mono Printer
        020b  OKI ES4140 Mono Printer
        02bb  OKI PT390 POS Printer
+       0383  MC563 Multifunction Printer
        0a91  B2500MFP (printer+scanner)
        3801  B6100 Laser Printer
 06bd  AGFA-Gevaert NV
        b4b5  SDDR-89 V4 ImageMate 12-in-1 Reader
        b6b7  SDDR-99 V4 ImageMate 5-in-1 Reader
        b6ba  CF SDDR-289
+       cfc9  SDDR-489 ImageMate Pro Reader
 0782  Trackerball
 0783  C3PO
        0003  LTC31 SmartCard Reader
 0968  Catalyst Enterprises, Inc.
 096e  Feitian Technologies, Inc.
        0005  ePass2000
+       0006  HID Dongle (for OEMs - manufacturer string is "OEM")
        0120  Microcosm Ltd Dinkey
        0305  ePass2000Auto
        0309  ePass3000GM
 0a5f  Zebra
        0009  LP2844 Printer
        0050  P120i / WM120i
+       0080  GK420d Label Printer
        0081  GK420t Label Printer
        0084  GX420d Desktop Label Printer
        008b  HC100 wristbands Printer
        ff01  Wireless Missile Launcher
 0a82  Syscan
        4600  TravelScan 460/464
+       6605  ScanShell 800N
 0a83  NextComm, Inc.
 0a84  Maui Innovative Peripherals
 0a85  Idexx Labs
        b728  RTL8723B Bluetooth
        b72a  RTL8723B Bluetooth
        b812  RTL88x2bu [AC1200 Techkey]
+       f179  RTL8188FTV 802.11b/g/n 1T1R 2.4G WLAN Adapter
 0bdb  Ericsson Business Mobile Networks BV
        1000  BV Bluetooth Device
        1002  Bluetooth Device 1.2
 0c3c  Radius Co., Ltd
 0c3d  Innocom, Inc.
 0c3e  Nextcell, Inc.
+0c40  ELMCU
+       8000  2.4GHz receiver
 0c44  Motorola iDEN
        0021  iDEN P2k0 Device
        0022  iDEN P2k1 Device
        1158  A56AK
        184c  VoIP Phone
        1a90  2M pixel Microscope Camera (with capture button) [Andonstar V160]
+       5004  Redragon Mitra RGB Keyboard
        5101  2.4G Wireless Device [Rii MX3]
        6001  Genius VideoCAM NB
        6005  Sweex Mini Webcam
 0f69  Dionex Corp.
 0f6a  Vibren Technologies, Inc.
 0f6e  INTELLIGENT SYSTEMS
-       0100  GameBoy Color Emulator
+       0100  IS-CGB-EMULATOR
        0201  GameBoy Advance Flash Gang Writer
-       0202  GameBoy Advance Capture
-       0300  Gamecube DOL Viewer
-       0400  NDS Emulator
-       0401  NDS UIC
-       0402  NDS Writer
-       0403  NDS Capture
-       0404  NDS Emulator (Lite)
+       0202  IS-AGB-CAPTURE
+       0300  IS-DOL-VIEWER
+       0400  IS-NITRO-EMULATOR
+       0401  IS-NITRO-UIC
+       0402  IS-NITRO-WRITER
+       0403  IS-NITRO-CAPTURE
+       0404  IS-NITRO-EMULATOR (DS Lite)
+       0500  IS-TWL-DEBUGGER
+       0501  IS-TWL-CAPTURE
 0f73  DFI
 0f78  Guntermann & Drunck GmbH
 0f7c  DQ Technology, Inc.
 1501  Pine-Tum Enterprise Co., Ltd.
 1504  Bixolon CO LTD
        001f  SRP-350II Thermal Receipt Printer
+1508  Fibocom
 1509  First International Computer, Inc.
        0a01  LI-3100 Area Meter
        0a02  LI-7000 CO2/H2O Gas Analyzer
        004a  RZ03-0133 Gaming Lapboard, Keyboard Mouse Combo, Dongle [Turret Dongle]
        004c  Diamondback Chroma
        004d  DeathAdder 2000 (Cynosa Pro Bundle)
+       004f  RZ01-0145, Gaming Mouse [DeathAdder 2000 (Alternate)]
        0050  Naga Hex V2
        0053  Naga Chroma
        0054  DeathAdder 3500
        007a  RC30-0305 Gaming Mouse [Viper Ultimate (Wired)]
        007b  RC30-0305 Gaming Mouse Dongle [Viper Ultimate (Wireless)]
        007e  RC30-030502 Mouse Dock
+       0083  RC30-0315, Gaming Mouse [Basilisk X HyperSpeed]
        0084  RZ01-0321 Gaming Mouse [DeathAdder V2]
        0085  RZ01-0316 Gaming Mouse [Basilisk V2]
-       0088  Razer Basilisk Ultimate Dongle
+       0086  Gaming Mouse [Basilisk Ultimate, Wired]
+       0088  Gaming Mouse [Basilisk Ultimate, Wireless, Receiver]
+       008a  RZ01-0325, Gaming Mouse [Viper Mini]
        0101  Copperhead Mouse
        0102  Tarantula Keyboard
        0103  Gaming Keyboard [Reclusa]
        024d  Blade 15 Studio Edition (2019)
        0253  RZ09-0330, Gaming Laptop [Blade 15 Advanced (Early 2020)]
        0255  RZ09-0328, Gaming Laptop [Blade 15 Base Model (2020)]
+       0256  RZ09--0329, Gaming Laptop [Blade Pro 17 Full HD (2020)]
+       025d  RZ03-0338, Gaming Keyboard [Ornata V2]
        0300  RZ06-0063 Motion Sensing Controllers [Hydra]
        0401  Gaming Arcade Stick [Panthera]
        0501  Kraken 7.1
        051a  Nari Ultimate
        051c  Nari (Wireless)
        051d  Nari (Wired)
+       051e  RC30-026902, Gaming Headset [Nari Essential, Wireless, Receiver]
+       051f  RC30-026901, Gaming Headset [Nari Essential, Wired]
        0520  Kraken Tournament Edition
        0521  Kraken Kitty Edition
        0527  RZ04-0318 Gaming Headset [Kraken Ultimate]
        0a00  Atrox Arcade Stick for Xbox One
        0a02  ManO'War
        0a03  Wildcat
+       0a15  RZ06-0199, Gaming Controller [Wolverine Tournament Edition]
        0c00  RZ02-0135 Hard Gaming Mouse Mat [Firefly]
        0c01  Goliathus
        0c02  Goliathus Extended
        8007  US-122 Audio/Midi Interface
 1605  ACCES I/O Products, Inc.
        0001  DIO-32 (No Firmware Yet)
+       0002  USB-DIO-48 (No Firmware Yet)
+       0003  USB-DIO-96 (No Firmware Yet)
+       0004  USB-DIO-32I (No Firmware Yet)
+       0005  USB-DIO24 (based on -CTR6) (No Firmware Yet)
+       0006  USB-DIO24-CTR6 (No Firmware Yet)
 1606  Umax
        0002  Astra 1236U Scanner
        0010  Astra 1220U
index 6db048b63be3035a10081922308a541a5313052a..479cbb5d92bc8e704f6358b018dc2c3902159255 100644 (file)
@@ -17,7 +17,7 @@
 
   <refnamediv>
     <refname>bootctl</refname>
-    <refpurpose>Control the firmware and boot manager settings</refpurpose>
+    <refpurpose>Control EFI firmware boot settings and manage boot loader</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
   <refsect1>
     <title>Description</title>
 
-    <para><command>bootctl</command> can check the EFI boot loader status, list available boot loaders and boot loader
-    entries, and install, update, or remove the
-    <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> boot loader on the
-    current system.</para>
+    <para><command>bootctl</command> can check the EFI firmware and boot loader status, list and manage
+    available boot loaders and boot loader entries, and install, update, or remove the
+    <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> boot
+    loader on the current system.</para>
   </refsect1>
 
   <refsect1>
-    <title>Commands</title>
-    <variablelist>
+    <title>Generic EFI Firmware/Boot Loader Commands</title>
+
+    <para>These commands are available on any EFI system, regardless of the boot loader used.</para>
 
+    <variablelist>
       <varlistentry>
         <term><option>status</option></term>
 
         loaders and the current default boot loader entry. If no command is specified, this is the implied
         default.</para></listitem>
       </varlistentry>
+    </variablelist>
+
+    <varlistentry>
+      <term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
+
+      <listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
+      boolean argument which controls whether to show the firmware setup on next system reboot. If the
+      argument is omitted shows the current status of the flag, or whether the flag is supported. This
+      controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
+      low-level and allows setting the flag independently from actually requesting a
+      reboot.</para></listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
+
+      <listitem><para>When called without the optional argument, prints the current value of the
+      <literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
+      variable to that value. See
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      for the meaning of that variable.</para></listitem>
+    </varlistentry>
+  </refsect1>
+
+  <refsect1>
+    <title>Boot Loader Specification Commands</title>
+
+    <para>These commands are available for all boot loaders that implement the <ulink
+    url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> and/or the <ulink
+    url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>, such as
+    <command>systemd-boot</command>.</para>
+
+    <variablelist>
 
+      <varlistentry>
+        <term><option>list</option></term>
+
+        <listitem><para>Shows all available boot loader entries implementing the <ulink
+        url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as well as any
+        other entries discovered or automatically generated by a boot loader implementing the <ulink
+        url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
+        Interface</ulink>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>set-default</option> <replaceable>ID</replaceable></term>
+        <term><option>set-oneshot</option> <replaceable>ID</replaceable></term>
+
+        <listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string as
+        argument. The <option>set-oneshot</option> command will set the default entry only for the next boot,
+        the <option>set-default</option> will set it persistently for all future boots.</para></listitem>
+
+        <listitem><para>Optionally, the boot loader entry ID may be specified as one of: <option>@default</option>,
+        <option>@oneshot</option> or <option>@current</option>, which correspond to the current default boot loader
+        entry for all future boots, the current default boot loader entry for the next boot, and the currently booted
+        boot loader entry. These special IDs are resolved to the current values of the EFI variables
+        <varname>LoaderEntryDefault</varname>, <varname>LoaderEntryOneShot</varname> and <varname>LoaderEntrySelected</varname>,
+        see <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> for details.
+        These special IDs are primarily useful as a quick way to persistently make the currently booted boot loader
+        entry the default choice, or to upgrade the default boot loader entry for the next boot to the default boot
+        loader entry for all future boots, but may be used for other operations too.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><command>systemd-boot</command> Commands</title>
+
+    <para>These commands manage the <command>systemd-boot</command> EFI boot loader, and do not work in
+    conjunction with other boot loaders.</para>
+
+    <variablelist>
       <varlistentry>
         <term><option>install</option></term>
 
         information.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
-
-        <listitem><para>When called without the optional argument, prints the current value of the
-        <literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
-        variable to that value. See
-        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-        for the meaning of that variable.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
-
-        <listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
-        boolean argument which controls whether to show the firmware setup on next system reboot. If the
-        argument is omitted shows the current status of the flag, or whether the flag is supported. This
-        controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
-        low-level and allows setting the flag independently from actually requesting a
-        reboot.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>list</option></term>
-
-        <listitem><para>Shows all available boot loader entries implementing the <ulink
-        url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
-        Specification</ulink>, as well as any other entries discovered or automatically generated by the boot
-        loader.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>set-default</option> <replaceable>ID</replaceable></term>
-        <term><option>set-oneshot</option> <replaceable>ID</replaceable></term>
-
-        <listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string as argument. The
-        <option>set-oneshot</option> command will set the default entry only for the next boot, the
-        <option>set-default</option> will set it persistently for all future boots.</para></listitem>
-      </varlistentry>
-
     </variablelist>
   </refsect1>
 
index 26f762bf816e220c3042fc37c6f22208853e628f..0c2edfc8a582bfab205a90876f7b184ba7ba3746 100644 (file)
@@ -227,7 +227,7 @@ emergency.service    |              |              |
     <filename>initrd-root-fs.target</filename> is reached. The service
     <filename>initrd-parse-etc.service</filename> scans
     <filename>/sysroot/etc/fstab</filename> for a possible
-    <filename>/usr</filename> mount point and additional entries
+    <filename>/usr/</filename> mount point and additional entries
     marked with the <emphasis>x-initrd.mount</emphasis> option. All
     entries found are mounted below <filename>/sysroot</filename>, and
     <filename>initrd-fs.target</filename> is reached. The service
index eebc42105d3fa27a381954e5595977cabdbb959c..06d17b201a89afbb31049b8539c5fdc83318af70 100644 (file)
           <para>Controls whether credential data reported by
           <command>list</command> or <command>status</command> shall
           be augmented with data from
-          <filename>/proc</filename>. When this is turned on, the data
+          <filename>/proc/</filename>. When this is turned on, the data
           shown is possibly inconsistent, as the data read from
-          <filename>/proc</filename> might be more recent than the rest of
+          <filename>/proc/</filename> might be more recent than the rest of
           the credential information. Defaults to <literal>yes</literal>.</para>
         </listitem>
       </varlistentry>
index ee54499bfe7a13c86869b3c7c4e355a0e7d511a5..567762751b8ed1176a30059e3d0b1a455f5312c0 100644 (file)
     device or file, or a specification of a block device via
     <literal>UUID=</literal> followed by the UUID.</para>
 
-    <para>The third field specifies an absolute path to a file to read the encryption key from. Optionally,
+    <para>The third field specifies an absolute path to a file with the encryption key. Optionally,
     the path may be followed by <literal>:</literal> and an fstab device specification (e.g. starting with
-    <literal>LABEL=</literal> or similar); in which case, the path is relative to the device file system
-    root. If the field is not present or set to <literal>none</literal> or <literal>-</literal>, a key file
+    <literal>LABEL=</literal> or similar); in which case the path is taken relative to the device file system
+    root. If the field is not present or is <literal>none</literal> or <literal>-</literal>, a key file
     named after the volume to unlock (i.e. the first column of the line), suffixed with
     <filename>.key</filename> is automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename>
     and <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to
       <varlistentry>
         <term><option>cipher=</option></term>
 
-        <listitem><para>Specifies the cipher to use. See
-        <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-        for possible values and the default value of this option. A
-        cipher with unpredictable IV values, such as
-        <literal>aes-cbc-essiv:sha256</literal>, is
-        recommended.</para></listitem>
+        <listitem><para>Specifies the cipher to use. See <citerefentry
+        project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        for possible values and the default value of this option. A cipher with unpredictable IV values, such
+        as <literal>aes-cbc-essiv:sha256</literal>, is recommended. Embedded commas in the cipher
+        specification need to be escaped by preceding them with a backslash, see example below.</para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         relevant for LUKS devices. See
         <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         for possible values and the default value of this
-        option.</para></listitem>
+        option.</para>
+
+        <para>Optionally, the path may be followed by <literal>:</literal> and an fstab device specification
+        (e.g. starting with <literal>UUID=</literal> or similar); in which case, the path is relative to the
+        device file system root. The device gets mounted automatically for LUKS device activation duration only.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
     <title>Examples</title>
     <example>
       <title>/etc/crypttab example</title>
-      <para>Set up four encrypted block devices. One using LUKS for
-      normal storage, another one for usage as a swap device and two
-      TrueCrypt volumes.</para>
+      <para>Set up four encrypted block devices. One using LUKS for normal storage, another one for usage as
+      a swap device and two TrueCrypt volumes. For the fourth device, the option string is interpreted as two
+      options <literal>cipher=xchacha12,aes-adiantum-plain64</literal>,
+      <literal>keyfile-timeout=10s</literal>.</para>
 
       <programlisting>luks       UUID=2505567a-9e27-4efe-a4d5-15ad146c258b
 swap       /dev/sda7       /dev/urandom       swap
 truecrypt  /dev/sda2       /etc/container_password  tcrypt
 hidden     /mnt/tc_hidden  /dev/null    tcrypt-hidden,tcrypt-keyfile=/etc/keyfile
-external   /dev/sda3       keyfile:LABEL=keydev keyfile-timeout=10s</programlisting>
+external   /dev/sda3       keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchacha12\,aes-adiantum-plain64
+</programlisting>
     </example>
 
     <example>
index 8b6394e927117692c2503e020878a91c5348e2a1..f14ebbce7cbe0fb49a9a678410ee5f3d2e36edf4 100644 (file)
     and follow the same overriding rules. They are text files with the
     <filename>.negative</filename> suffix. Empty lines and lines whose first character is
     <literal>;</literal> are ignored. Each line specifies one domain name which is the root of a DNS
-    subtree where validation shall be disabled.</para>
+    subtree where validation shall be disabled. For example:</para>
+
+    <programlisting># Reverse IPv4 mappings
+10.in-addr.arpa
+16.172.in-addr.arpa
+168.192.in-addr.arpa
+...
+# Some custom domains
+prod
+stag
+</programlisting>
 
     <para>Negative trust anchors are useful to support private DNS
     subtrees that are not referenced from the Internet DNS hierarchy,
index 0f53b0fef106780c6b58de53089c3cd155f5af69..4db44616a733aa1cac798b73b70b8c66b77536a1 100644 (file)
@@ -76,7 +76,7 @@
         <title>Setup environment to allow access to a program installed in
         <filename index="false">/opt/foo</filename></title>
 
-        <para><filename>/etc/environment.d/60-foo.conf</filename>:
+        <para><filename index="false">/etc/environment.d/60-foo.conf</filename>:
         </para>
         <programlisting>
         FOO_DEBUG=force-software-gl,log-verbose
index d5899dc362183d90402d6b5c8354e8aedadaecbe..996876f48a379bcae1390bf7921144f6e9d4d3b4 100644 (file)
         <term><filename>/tmp/</filename></term>
         <listitem><para>The place for small temporary files. This directory is usually mounted as a
         <literal>tmpfs</literal> instance, and should hence not be used for larger files. (Use
-        <filename>/var/tmp/</filename> for larger files.) Since the directory is accessible to other users of
-        the system, it is essential that this directory is only written to with the <citerefentry
-        project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-        <citerefentry
-        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
-        related calls. This directory is usually flushed at boot-up. Also, files that are not accessed within
-        a certain time are usually automatically deleted. If applications find the environment variable
-        <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over directly
-        referencing <filename>/tmp/</filename> (see <citerefentry
+        <filename>/var/tmp/</filename> for larger files.) This directory is usually flushed at boot-up. Also,
+        files that are not accessed within a certain time may be automatically deleted.</para>
+
+        <para>If applications find the environment variable <varname>$TMPDIR</varname> set, they should use
+        the directory specified in it instead of <filename>/tmp/</filename> (see <citerefentry
         project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> and
         <ulink url="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03">IEEE
-        Std 1003.1</ulink> for details). For further details about this directory, see <ulink
-        url="https://systemd.io/TEMPORARY_DIRECTORIES">Using /tmp/ And /var/tmp/
-        Safely</ulink>.</para></listitem>
+        Std 1003.1</ulink> for details).</para>
+
+        <para>Since <filename>/tmp/</filename> is accessible to other users of the system, it is essential
+        that files and subdirectories under this directory are only created with <citerefentry
+        project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        <citerefentry
+        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        and similar calls. For more details, see <ulink url="https://systemd.io/TEMPORARY_DIRECTORIES">Using
+        /tmp/ and /var/tmp/ Safely</ulink>.</para>
+        </listitem>
       </varlistentry>
 
     </variablelist>
         <term><filename>/var/tmp/</filename></term>
         <listitem><para>The place for larger and persistent temporary files. In contrast to
         <filename>/tmp/</filename>, this directory is usually mounted from a persistent physical file system
-        and can thus accept larger files. (Use <filename>/tmp/</filename> for smaller files.) This directory
-        is generally not flushed at boot-up, but time-based cleanup of files that have not been accessed for
-        a certain time is applied. The same security restrictions as with <filename>/tmp/</filename> apply,
-        and hence only <citerefentry
+        and can thus accept larger files. (Use <filename>/tmp/</filename> for small ephemeral files.) This
+        directory is generally not flushed at boot-up, but time-based cleanup of files that have not been
+        accessed for a certain time is applied.</para>
+
+        <para>If applications find the environment variable <varname>$TMPDIR</varname> set, they should use
+        the directory specified in it instead of <filename>/var/tmp/</filename> (see <citerefentry
+        project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details).</para>
+
+        <para>The same security restrictions as with <filename>/tmp/</filename> apply: <citerefentry
         project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
         <citerefentry
-        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
-        similar calls should be used to make use of this directory.  If applications find the environment
-        variable <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over
-        directly referencing <filename>/var/tmp/</filename> (see <citerefentry
-        project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
-        details). For further details about this directory, see <ulink
-        url="https://systemd.io/TEMPORARY_DIRECTORIES">Using /tmp/ And /var/tmp/
-        Safely</ulink>.</para></listitem>
+        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        and similar calls should be used. For further details about this directory, see <ulink
+        url="https://systemd.io/TEMPORARY_DIRECTORIES">Using /tmp/ and /var/tmp/ Safely</ulink>.</para>
+        </listitem>
       </varlistentry>
 
     </variablelist>
     directives of service units (see
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for details).</para>
+
+    <para><filename>/tmp/</filename>, <filename>/var/tmp/</filename> and <filename>/dev/shm/</filename>
+    should be mounted <option>nosuid</option> and <option>nodev</option>, which means that set-user-id mode
+    and character or block special devices are not interpreted on those file systems. In general it is not
+    possible to mount them <option>noexec</option>, because various programs use those directories for
+    dynamically generated or optimized code, and with that flag those use cases would break. Using this flag
+    is OK on special-purpose installations or systems where all software that may be installed is known and
+    doesn't require such functionality. See the discussion of
+    <option>nosuid</option>/<option>nodev</option>/<option>noexec</option> in <citerefentry
+    project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
+    <constant>PROT_EXEC</constant> in <citerefentry
+    project='man-pages'><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+    </para>
   </refsect1>
 
   <refsect1>
   <refsect1>
     <title>System Packages</title>
 
-    <para>Developers of system packages should follow strict rules
-    when placing their own files in the file system. The following
-    table lists recommended locations for specific types of files
-    supplied by the vendor.</para>
+    <para>Developers of system packages should follow strict rules when placing their files in the file
+    system. The following table lists recommended locations for specific types of files supplied by the
+    vendor.</para>
 
     <table>
-      <title>System Package Vendor Files Locations</title>
+      <title>System package vendor files locations</title>
       <tgroup cols='2' align='left' colsep='1' rowsep='1'>
         <colspec colname="directory" />
         <colspec colname="purpose" />
     <filename>/usr/share/</filename> hierarchy to the locations
     defined by the various relevant specifications.</para>
 
-    <para>During runtime, and for local configuration and runtime state,
-    additional directories are defined:</para>
+    <para>The following directories shall be used by the package for local configuration and files created
+    during runtime:</para>
 
     <table>
-      <title>System Package Variable Files Locations</title>
+      <title>System package variable files locations</title>
       <tgroup cols='2' align='left' colsep='1' rowsep='1'>
         <colspec colname="directory" />
         <colspec colname="purpose" />
   <refsect1>
     <title>User Packages</title>
 
-    <para>Programs running in user context should follow strict rules
-    when placing their own files in the user's home directory. The
-    following table lists recommended locations in the home directory
-    for specific types of files supplied by the vendor if the
-    application is installed in the home directory. (Note, however,
-    that user applications installed system-wide should follow the
-    rules outlined above regarding placing vendor files.)</para>
+    <para>Programs running in user context should follow strict rules when placing their own files in the
+    user's home directory. The following table lists recommended locations in the home directory for specific
+    types of files supplied by the vendor if the application is installed in the home directory. (User
+    applications installed system-wide are covered by the rules outlined above for vendor files.)</para>
 
     <table>
-      <title>User Package Vendor File Locations</title>
+      <title>Vendor package file locations under the home directory of the user</title>
       <tgroup cols='2' align='left' colsep='1' rowsep='1'>
         <colspec colname="directory" />
         <colspec colname="purpose" />
           </row>
           <row>
       <entry><filename>~/.local/lib/<replaceable>arch-id</replaceable>/</filename></entry>
-      <entry>Public shared libraries of the package. As above, be careful with using too generic names, and pick unique names for your libraries to place here to avoid name clashes.</entry>
+      <entry>Public shared libraries of the package. As above, be careful with using overly generic names, and pick unique names for your libraries to place here to avoid name clashes.</entry>
           </row>
           <row>
       <entry><filename>~/.local/lib/<replaceable>package</replaceable>/</filename></entry>
       </tgroup>
     </table>
 
-    <para>Additional static vendor files may be installed in the
-    <filename>~/.local/share/</filename> hierarchy to the locations
-    defined by the various relevant specifications.</para>
+    <para>Additional static vendor files may be installed in the <filename>~/.local/share/</filename>
+    hierarchy, mirroring the subdirectories specified in the section "Vendor-supplied operating system
+    resources" above.</para>
 
-    <para>During runtime, and for local configuration and state,
-    additional directories are defined:</para>
+    <para>The following directories shall be used by the package for per-user local configuration and files
+    created during runtime:</para>
 
     <table>
-      <title>User Package Variable File Locations</title>
+      <title>User package variable file locations</title>
       <tgroup cols='2' align='left' colsep='1' rowsep='1'>
         <colspec colname="directory" />
         <colspec colname="purpose" />
index dd16e47bebf1171df4140e9a527771405a742367..8afe993dac1bef87fe66598b3c14ea7d34fb8293 100644 (file)
 
         <listitem><para>Read the user's JSON record from the specified file. If passed as
         <literal>-</literal> read the user record from standard input. The supplied JSON object must follow
-        the structure documented on <ulink url="https://systemd.io/USER_RECORD">JSON User Records</ulink>.
+        the structure documented in <ulink url="https://systemd.io/USER_RECORD">JSON User Records</ulink>.
         This option may be used in conjunction with the <command>create</command> and
         <command>update</command> commands (see below), where it allows configuring the user record in JSON
         as-is, instead of setting the individual user record properties (see below).</para></listitem>
       <varlistentry>
         <term><option>--timezone=</option><replaceable>TIMEZONE</replaceable></term>
 
-        <listitem><para>Takes a timezone specification as string that sets the timezone for the specified
-        user. Expects a `tzdata` location string. When the user logs in the <varname>$TZ</varname>
-        environment variable is initialized from this setting. Example:
-        <option>--timezone=Europe/Amsterdam</option> will result in the environment variable
-        <literal>TZ=:Europe/Amsterdam</literal>.</para></listitem>
+        <listitem><para>Takes a time zone location name that sets the timezone for the specified user. When
+        the user logs in the <varname>$TZ</varname> environment variable is initialized from this
+        setting. Example: <option>--timezone=Europe/Amsterdam</option> will result in the environment
+        variable <literal>TZ=:Europe/Amsterdam</literal>. (<literal>:</literal> is used intentionally as part
+        of the timezone specification, see
+        <citerefentry project='man-pages'><refentrytitle>tzset</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
 
         <listitem><para>Takes a path to a Linux <literal>hidraw</literal> device
         (e.g. <filename>/dev/hidraw1</filename>), referring to a FIDO2 security token implementing the
-        <literal>hmac-secret</literal> extension, that shall be able to unlock the user account. If used, a
-        random salt value is generated on the host, which is passed to the FIDO2 device, which calculates a
-        HMAC hash of it, keyed by its internal secret key. The result is then used as key for unlocking the
-        user account. The random salt is included in the user record, so that whenever authentication is
-        needed it can be passed again to the FIDO2 token, to retrieve the actual key.</para>
+        <literal>hmac-secret</literal> extension that shall be able to unlock the user account. A random salt
+        value is generated on the host and passed to the FIDO2 device, which calculates a HMAC hash of the
+        salt using an internal secret key. The result is then used as the key to unlock the user account. The
+        random salt is included in the user record, so that whenever authentication is needed it can be
+        passed to the FIDO2 token again.</para>
 
         <para>Instead of a valid path to a FIDO2 <literal>hidraw</literal> device the special strings
         <literal>list</literal> and <literal>auto</literal> may be specified. If <literal>list</literal> is
 
         <listitem><para>Takes a password hint to store alongside the user record. This string is stored
         accessible only to privileged users and the user itself and may not be queried by other users.
-        Example: <option>--password-hint="My first pet's name"</option></para></listitem>
+        Example: <option>--password-hint="My first pet's name"</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         their home directories are removed from memory.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><command>deactivate-all</command></term>
+
+        <listitem><para>Execute the <command>deactivate</command> command on all active home directories at
+        once. This operation is generally executed on system shut down (i.e. by <command>systemctl
+        poweroff</command> and related commands), to ensure all active user's home directories are fully
+        deactivated before <filename>/home/</filename> and related file systems are unmounted.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><command>with</command> <replaceable>USER</replaceable> <replaceable>COMMAND…</replaceable></term>
 
index 23b77ebbb068bfe703d6a99ad49cbb450c2df6fc..c142f581de010f4002c07976215d932bcb3b6bc2 100755 (executable)
@@ -13,7 +13,7 @@ target="man/$1.html"
 ninja -C "@BUILD_ROOT@" "$target"
 
 fullname="@BUILD_ROOT@/$target"
-redirect="$(readlink "$fullname" 2>/dev/null)"
+redirect="$(test -f "$fullname" && readlink "$fullname" || :)"
 if [ -n "$redirect" ]; then
     ninja -C "@BUILD_ROOT@" "man/$redirect"
 
index 7ba523602a7bec28df2f9c67ab3e9ceec8c433e3..5e906907472c15592bddae81fae698c8980c18a8 100644 (file)
       the local administration directory <filename>/etc/udev/hwdb.d</filename>.
       All hwdb files are collectively sorted and processed in lexical order,
       regardless of the directories in which they live. However, files with
-      identical filenames replace each other. Files in <filename>/etc</filename>
+      identical filenames replace each other. Files in <filename>/etc/</filename>
       have the highest priority and take precedence over files with the same
-      name in <filename>/usr/lib</filename>. This can be used to override a
+      name in <filename>/usr/lib/</filename>. This can be used to override a
       system-supplied hwdb file with a local file if needed;
-      a symlink in <filename>/etc</filename> with the same name as a hwdb file in
-      <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>,
+      a symlink in <filename>/etc/</filename> with the same name as a hwdb file in
+      <filename>/usr/lib/</filename>, pointing to <filename>/dev/null</filename>,
       disables that hwdb file entirely. hwdb files must have the extension
       <filename>.hwdb</filename>; other extensions are ignored.</para>
 
       they are combined by OR. Every match line must start at the first character of the
       line.</para>
 
+      <para>Match patterns consist of literal characters, and shell-style wildcards:</para>
+      <itemizedlist>
+        <listitem><para>Asterisk <literal>*</literal> matches any number of characters
+        </para></listitem>
+        <listitem><para>Question mark <literal>?</literal> matches a single character
+        </para></listitem>
+        <listitem><para>Character list <literal>[<replaceable>chars</replaceable>]</literal> matches one of
+        the characters <replaceable>chars</replaceable> listed between <literal>[</literal> and
+        <literal>]</literal>. A range may be specified as with a dash as
+        <literal>[<replaceable>first</replaceable>-<replaceable>last</replaceable>]</literal>. The match may
+        be inverted with a caret <literal>[^…]</literal>.</para></listitem>
+      </itemizedlist>
+
       <para>The match lines are followed by one or more key-value pair lines, which are
       recognized by a leading space character. The key name and value are separated by
       <literal>=</literal>. An empty line signifies the end of a record. Lines beginning
 # it defines, and the ordering convention.
 
 # A record with three matches and one property
-mouse:*:name:*Trackball*:
-mouse:*:name:*trackball*:
-mouse:*:name:*TrackBall*:
+mouse:*:name:*Trackball*:*
+mouse:*:name:*trackball*:*
+mouse:*:name:*TrackBall*:*
+ ID_INPUT_TRACKBALL=1
+
+# The rule above could be also be written in a form that
+# matches Tb, tb, TB, tB:
+mouse:*:name:*[tT]rack[bB]all*:*
  ID_INPUT_TRACKBALL=1
 
 # A record with a single match and five properties
-mouse:usb:v046dp4041:name:Logitech MX Master:
+mouse:usb:v046dp4041:name:Logitech MX Master:*
  MOUSE_DPI=1000@166
  MOUSE_WHEEL_CLICK_ANGLE=15
  MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
@@ -98,26 +116,30 @@ mouse:usb:v046dp4041:name:Logitech MX Master:
       <title>Overriding of properties</title>
 
       <programlisting># /usr/lib/udev/hwdb.d/60-keyboard.hwdb
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*:*
  KEYBOARD_KEY_a1=help
  KEYBOARD_KEY_a2=setup
  KEYBOARD_KEY_a3=battery
 
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn123*
+# Match vendor name "Acer" and any product name starting with "X123"
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer:pnX123*:*
  KEYBOARD_KEY_a2=wlan
 
 # /etc/udev/hwdb.d/70-keyboard.hwdb
 # disable wlan key on all at keyboards
 evdev:atkbd:*
- KEYBOARD_KEY_a2=reserved</programlisting>
+ KEYBOARD_KEY_a2=reserved
+ PROPERTY_WITH_SPACES=some string</programlisting>
 
       <para>If the hwdb consists of those two files, a keyboard with the lookup string
-      <literal>evdev:atkbd:dmi:bvnAcer:bdXXXXX:bd08/05/2010:svnAcer:pn123</literal>
+      <literal>evdev:atkbd:dmi:bvnAcer:bdXXXXX:bd08/05/2010:svnAcer:pnX123</literal>
       will match all three records, and end up with the following properties:</para>
 
       <programlisting>KEYBOARD_KEY_a1=help
 KEYBOARD_KEY_a2=reserved
-KEYBOARD_KEY_a3=battery</programlisting>
+KEYBOARD_KEY_a3=battery
+PROPERTY_WITH_SPACES=some string</programlisting>
+
     </example>
   </refsect1>
 
index d792ef7220f7f3f2d1ae8d1944777c731fe5e419..2281e069d50917e395c0155f5f88ddd9247d786f 100644 (file)
         with <literal>Runtime</literal> apply to the journal files
         when stored on a volatile in-memory file system, more
         specifically <filename>/run/log/journal</filename>. The former
-        is used only when <filename>/var</filename> is mounted,
+        is used only when <filename>/var/</filename> is mounted,
         writable, and the directory
         <filename>/var/log/journal</filename> exists. Otherwise, only
         the latter applies. Note that this means that during early
index b0b45f4c62fc79f830fba691c0a3336aa61ec089..8f61188a63d1b455f33d5e17bc3a305a157428fb 100644 (file)
         <listitem>
           <para>This parameter controls whether the system shall boot up in volatile mode. Takes a boolean argument, or
           the special value <literal>state</literal>. If false (the default), normal boot mode is selected, the root
-          directory and <filename>/var</filename> are mounted as specified on the kernel command line or
+          directory and <filename>/var/</filename> are mounted as specified on the kernel command line or
           <filename>/etc/fstab</filename>, or otherwise configured. If true, full state-less boot mode is selected. In
           this case the root directory is mounted as volatile memory file system (<literal>tmpfs</literal>), and only
-          <filename>/usr</filename> is mounted from the file system configured as root device, in read-only mode. This
+          <filename>/usr/</filename> is mounted from the file system configured as root device, in read-only mode. This
           enables fully state-less boots were the vendor-supplied OS is used as shipped, with only default
-          configuration and no stored state in effect, as <filename>/etc</filename> and <filename>/var</filename> (as
+          configuration and no stored state in effect, as <filename>/etc/</filename> and <filename>/var/</filename> (as
           well as all other resources shipped in the root file system) are reset at boot and lost on shutdown. If this
           setting is set to <literal>state</literal> the root file system is mounted read-only, however
-          <filename>/var</filename> is mounted as a volatile memory file system (<literal>tmpfs</literal>), so that the
+          <filename>/var/</filename> is mounted as a volatile memory file system (<literal>tmpfs</literal>), so that the
           system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. If
           this setting is set to <literal>overlay</literal> the root file system is set up as
           <literal>overlayfs</literal> mount combining the read-only root directory with a writable
index 08e513c99f8e9d52f5db5dfc0ec988bc0337f856..049e9f75d7f212760f6af036b1bc74a24447968b 100644 (file)
       the invoking terminal is determined to be UTF-8 compatible).</para></listitem>
     </varlistentry>
 
+    <varlistentry id='lesssecure'>
+      <term><varname>$SYSTEMD_PAGERSECURE</varname></term>
+
+      <listitem><para>Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if
+      false, disabled. If <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, secure mode is enabled
+      if the effective UID is not the same as the owner of the login session, see <citerefentry
+      project='man-pages'><refentrytitle>geteuid</refentrytitle><manvolnum>2</manvolnum></citerefentry> and
+      <citerefentry><refentrytitle>sd_pid_get_owner_uid</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+      In secure mode, <option>LESSSECURE=1</option> will be set when invoking the pager, and the pager shall
+      disable commands that open or create new files or start new subprocesses. When
+      <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, pagers which are not known to implement
+      secure mode will not be used. (Currently only
+      <citerefentry><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> implements
+      secure mode.)</para>
+
+      <para>Note: when commands are invoked with elevated privileges, for example under <citerefentry
+      project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
+      <citerefentry
+      project='die-net'><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>, care
+      must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the
+      pager may be enabled automatically as describe above. Setting <varname>SYSTEMD_PAGERSECURE=0</varname>
+      or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note
+      that if the <varname>$SYSTEMD_PAGER</varname> or <varname>$PAGER</varname> variables are to be
+      honoured, <varname>$SYSTEMD_PAGERSECURE</varname> must be set too. It might be reasonable to completly
+      disable the pager using <option>--no-pager</option> instead.</para></listitem>
+    </varlistentry>
+
     <varlistentry id='colors'>
       <term><varname>$SYSTEMD_COLORS</varname></term>
 
index 05a4c75c7930716cea54e5197b45c01cdca197d3..acc5aa9a6f2a0eb2b6b988f8a12f4a19959e1381 100644 (file)
 
         <listitem><para>Persistently attach one or more devices to a
         seat. The devices should be specified via device paths in the
-        <filename>/sys</filename> file system. To create a new seat,
+        <filename>/sys/</filename> file system. To create a new seat,
         attach at least one graphics card to a previously unused seat
         name. Seat names may consist only of a–z, A–Z, 0–9,
         <literal>-</literal> and <literal>_</literal> and must be
index 97d11da03fa436f9d10270bef618fc75d473112e..7857073acacaa00d7c3c49922f93f10c361ef237 100644 (file)
         <term><varname>KillOnlyUsers=</varname></term>
         <term><varname>KillExcludeUsers=</varname></term>
 
-        <listitem><para>These settings take space-separated lists of usernames that override
-        the <varname>KillUserProcesses=</varname> setting. A user name may be added to
-        <varname>KillExcludeUsers=</varname> to exclude the processes in the session scopes of
-        that user from being killed even if <varname>KillUserProcesses=yes</varname> is set. If
-        <varname>KillExcludeUsers=</varname> is not set, the <literal>root</literal> user is
-        excluded by default. <varname>KillExcludeUsers=</varname> may be set to an empty value
-        to override this default. If a user is not excluded, <varname>KillOnlyUsers=</varname>
-        is checked next. If this setting is specified, only the session scopes of those users
-        will be killed. Otherwise, users are subject to the
-        <varname>KillUserProcesses=yes</varname> setting.</para></listitem>
+        <listitem><para>These settings take space-separated lists of usernames that override the
+        <varname>KillUserProcesses=</varname> setting. A user name may be added to
+        <varname>KillExcludeUsers=</varname> to exclude the processes in the session scopes of that user from
+        being killed even if <varname>KillUserProcesses=yes</varname> is set. If
+        <varname>KillExcludeUsers=</varname> is not set, the <literal>root</literal> user is excluded by
+        default. <varname>KillExcludeUsers=</varname> may be set to an empty value to override this
+        default. If a user is not excluded, <varname>KillOnlyUsers=</varname> is checked next. If this
+        setting is specified, only the processes in the session scopes of those users will be
+        killed. Otherwise, users are subject to the <varname>KillUserProcesses=yes</varname> setting.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
index bd55366ac8805a739ac2d7f4e76a387d1f2b5ec6..7e889ca47a9e09fd40f35a451c701277d5d8de7a 100644 (file)
 
     <para>For operating system images which are created once and used on multiple
     machines, for example for containers or in the cloud,
-    <filename>/etc/machine-id</filename> should be an empty file in the generic file
-    system image. An ID will be generated during boot and saved to this file if
-    possible. Having an empty file in place is useful because it allows a temporary file
-    to be bind-mounted over the real file, in case the image is used read-only.</para>
+    <filename>/etc/machine-id</filename> should be either missing or an empty file in the generic file
+    system image (the difference between the two options is described under "First Boot Semantics" below). An
+    ID will be generated during boot and saved to this file if possible. Having an empty file in place is
+    useful because it allows a temporary file to be bind-mounted over the real file, in case the image is
+    used read-only.</para>
 
     <para><citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     may be used to initialize <filename>/etc/machine-id</filename> on mounted (but not
 
     <para><citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
     will attempt to write the machine ID to the file system if
-    <filename>/etc/machine-id</filename> or <filename>/etc</filename> are read-only during
+    <filename>/etc/machine-id</filename> or <filename>/etc/</filename> are read-only during
     early boot but become writable later on.</para>
   </refsect1>
 
+  <refsect1>
+    <title>First Boot Semantics</title>
+
+    <para><filename>/etc/machine-id</filename> is used to decide whether a boot is the first one.  The rules
+    are as follows:</para>
+
+    <orderedlist>
+      <listitem><para>If <filename>/etc/machine-id</filename> does not exist, this is a first boot.  During
+      early boot, <command>systemd</command> will write <literal>unitialized\n</literal> to this file and overmount
+      a temporary file which contains the actual machine ID.  Later (after <filename>first-boot-complete.target</filename>
+      has been reached), the real machine ID will be written to disk.</para></listitem>
+
+      <listitem><para>If <filename>/etc/machine-id</filename> contains the string <literal>uninitialized</literal>,
+      a boot is also considered the first boot.  The same mechanism as above applies.</para></listitem>
+
+      <listitem><para>If <filename>/etc/machine-id</filename> exists and is empty, a boot is
+      <emphasis>not</emphasis> considered the first boot.  <command>systemd</command> will still bind-mount a file
+      containing the actual machine-id over it and later try to commit it to disk (if <filename>/etc/</filename> is
+      writable).</para></listitem>
+
+      <listitem><para>If <filename>/etc/machine-id</filename> already contains a valid machine-id, this is
+      not a first boot.</para></listitem>
+    </orderedlist>
+
+    <para>If by any of the above rules, a first boot is detected, units with <varname>ConditionFirstBoot=yes</varname>
+    will be run.</para>
+  </refsect1>
+
   <refsect1>
     <title>Relation to OSF UUIDs</title>
 
index 37e51f90cf2718bb6c4bf0eee79e706351d536e9..5f940459840728620edfa3d47037e01d718a7485 100644 (file)
@@ -64,8 +64,8 @@
 
     <itemizedlist>
       <listitem><para>Directory trees containing an OS, including the
-      top-level directories <filename>/usr</filename>,
-      <filename>/etc</filename>, and so on.</para></listitem>
+      top-level directories <filename>/usr/</filename>,
+      <filename>/etc/</filename>, and so on.</para></listitem>
 
       <listitem><para>btrfs subvolumes containing OS trees, similar to regular directory trees.</para></listitem>
 
         <term><command>clean</command></term>
 
         <listitem><para>Remove hidden VM or container images (or all). This command removes all hidden machine images
-        from <filename>/var/lib/machines</filename>, i.e. those whose name begins with a dot. Use <command>machinectl
+        from <filename>/var/lib/machines/</filename>, i.e. those whose name begins with a dot. Use <command>machinectl
         list-images --all</command> to see a list of all machine images, including the hidden ones.</para>
 
         <para>When combined with the <option>--all</option> switch removes all images, not just hidden ones. This
-        command effectively empties <filename>/var/lib/machines</filename>.</para>
+        command effectively empties <filename>/var/lib/machines/</filename>.</para>
 
         <para>Note that commands such as <command>machinectl pull-tar</command> or <command>machinectl
         pull-raw</command> usually create hidden, read-only, unmodified machine images from the downloaded image first,
         <command>import-tar</command> is used, the file specified as
         the first argument should be a tar archive, possibly compressed
         with xz, gzip or bzip2. It will then be unpacked into its own
-        subvolume in <filename>/var/lib/machines</filename>. When
+        subvolume in <filename>/var/lib/machines/</filename>. When
         <command>import-raw</command> is used, the file should be a
         qcow2 or raw disk image, possibly compressed with xz, gzip or
         bzip2. If the second argument (the resulting image name) is
     <filename>/usr/lib/machines/</filename>. For compatibility reasons,
     the directory <filename>/var/lib/container/</filename> is
     searched, too. Note that images stored below
-    <filename>/usr</filename> are always considered read-only. It is
+    <filename>/usr/</filename> are always considered read-only. It is
     possible to symlink machines images from other directories into
     <filename>/var/lib/machines/</filename> to make them available for
     control with <command>machinectl</command>.</para>
index 3c2c7023ed08f325a22b3ed50b4cabba367176e4..d056ad0c71f0537eb53184f28e3c4aeb62db579e 100644 (file)
@@ -207,7 +207,7 @@ if dbus_docs.length() > 0
                            '@INPUT@'],
                 input : dbus_docs)
 
-        if conf.get('DEVELOPER_MODE') == 1
+        if conf.get('BUILD_MODE') == 'BUILD_MODE_DEVELOPER'
                 test('dbus-docs-fresh',
                      update_dbus_docs_py,
                      args : ['--build-dir=@0@'.format(project_build_root),
index b424f1fbd2500c97c18999d864ca5fb6e1ed453e..e12d9bf5b2b41495a308ae963b0bea132aa067e0 100644 (file)
@@ -57,7 +57,7 @@
     hostname. When using dynamic hostnames, this is traditionally
     achieved by patching <filename>/etc/hosts</filename> at the same
     time as changing the hostname. This is problematic since it
-    requires a writable <filename>/etc</filename> file system and is
+    requires a writable <filename>/etc/</filename> file system and is
     fragile because the file might be edited by the administrator at
     the same time. With <command>nss-myhostname</command> enabled,
     changing <filename>/etc/hosts</filename> is unnecessary, and on
diff --git a/man/oomctl.xml b/man/oomctl.xml
new file mode 100644 (file)
index 0000000..10633b9
--- /dev/null
@@ -0,0 +1,86 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="oomctl" conditional='ENABLE_OOMD'
+  xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>oomctl</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>oomctl</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>oomctl</refname>
+    <refpurpose>Analyze the state stored in <command>systemd-oomd</command></refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>oomctl</command>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
+      <arg choice="req">COMMAND</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>oomctl</command> may be used to get information about the various contexts read in by
+    the <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> userspace
+    out-of-memory (OOM) killer,
+    <citerefentry><refentrytitle>systemd-oomd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Commands</title>
+
+    <para>The following commands are understood:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term><command>dump</command></term>
+
+        <listitem><para>Show the current state of the cgroup(s) and system context(s) stored by
+        <command>systemd-oomd</command>.</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+
+    <para>The following options are understood:</para>
+
+    <variablelist>
+      <xi:include href="standard-options.xml" xpointer="help" />
+      <xi:include href="standard-options.xml" xpointer="version" />
+      <xi:include href="standard-options.xml" xpointer="no-pager" />
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Exit status</title>
+
+    <para>On success, 0 is returned, a non-zero failure code otherwise.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
diff --git a/man/oomd.conf.xml b/man/oomd.conf.xml
new file mode 100644 (file)
index 0000000..e6be947
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="oomd.conf" conditional='ENABLE_OOMD'
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>oomd.conf</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>oomd.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>oomd.conf</refname>
+    <refname>oomd.conf.d</refname>
+    <refpurpose>Global <command>systemd-oomd</command> configuration files</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/systemd/oomd.conf</filename></para>
+    <para><filename>/etc/systemd/oomd.conf.d/*.conf</filename></para>
+    <para><filename>/usr/lib/systemd/oomd.conf.d/*.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These files configure the various parameters of the
+    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> userspace
+    out-of-memory (OOM) killer,
+    <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+    See <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    for a general description of the syntax.</para>
+
+  </refsect1>
+
+  <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+  <refsect1>
+    <title>[OOM] Section Options</title>
+
+    <para>The following options are available in the [OOM] section:</para>
+
+    <variablelist class='config-directives'>
+      <varlistentry>
+        <term><varname>SwapUsedLimitPercent=</varname></term>
+
+        <listitem><para>Sets the limit for swap usage on the system before <command>systemd-oomd</command> will
+        take action. If the percentage of swap used on the system is more than what is defined here,
+        <command>systemd-oomd</command> will act on eligible descendant cgroups, starting from the ones with the
+        highest swap usage to the lowest swap usage. Which cgroups are monitored and what
+        action gets taken depends on what the unit has configured for <varname>ManagedOOMSwap=</varname>.
+        Takes a percentage value between 0% and 100%, inclusive. Defaults to 90%.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>DefaultMemoryPressureLimitPercent=</varname></term>
+
+        <listitem><para>Sets the limit for memory pressure on the unit's cgroup before <command>systemd-oomd</command>
+        will take action. A unit can override this value with <varname>ManagedOOMMemoryPressureLimitPercent=</varname>.
+        The memory pressure for this property represents the fraction of time in a 10 second window in which all tasks
+        in the cgroup were delayed. For each monitored cgroup, if the memory pressure on that cgroup exceeds the
+        limit set for more than 30 seconds, <command>systemd-oomd</command> will act on eligible descendant cgroups,
+        starting from the ones with the most reclaim activity to the least reclaim activity. Which cgroups are
+        monitored and what action gets taken depends on what the unit has configured for
+        <varname>ManagedOOMMemoryPressure=</varname>. Takes a percentage value between 0% and 100%, inclusive.
+        Defaults to 60%.</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+      <title>See Also</title>
+      <para>
+        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>oomctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      </para>
+  </refsect1>
+
+</refentry>
index 73f868248097ca9dfc1509659a983c857254ed57..8d3defbfe035c986412fc6ce4e5931e921ab010f 100644 (file)
@@ -95,6 +95,7 @@ node /org/freedesktop/home1 {
               out h send_fd);
       ReleaseHome(in  s user_name);
       LockAllHomes();
+      DeactivateAllHomes();
     properties:
       readonly a(sso) AutoLogin = [...];
   };
@@ -156,6 +157,8 @@ node /org/freedesktop/home1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="LockAllHomes()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="DeactivateAllHomes()"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="AutoLogin"/>
 
     <!--End of Autogenerated section-->
@@ -340,6 +343,9 @@ node /org/freedesktop/home1 {
       <para><function>LockAllHomes()</function> locks all active home directories that only have references
       that opted into automatic suspending during system suspend. This is usually invoked automatically
       shortly before system suspend.</para>
+
+      <para><function>DeactivateAllHomes()</function> deactivates all home areas that are currently
+      active. This is usually invoked automatically shortly before system shutdown.</para>
     </refsect2>
 
     <refsect2>
index 56ce9f0b4503c9bab7f86cd37ac63776f46a1ce7..472b9f999e879753fa8c53701ee30c665c743bfb 100644 (file)
@@ -156,7 +156,7 @@ node /org/freedesktop/import1 {
       operation (as in that case we know the total size on disk). If a socket or pipe is specified, progress information is not
       available. The file descriptor argument is followed by a local name for the image. This should be a
       name suitable as a hostname and will be used to name the imported image below
-      <filename>/var/lib/machines</filename>. A tar import is placed as a directory tree or a
+      <filename>/var/lib/machines/</filename>. A tar import is placed as a directory tree or a
       <citerefentry project="man-pages"><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       subvolume below <filename>/var/lib/machines/</filename> under the specified name with no suffix
       appended. A raw import is placed as a file in <filename>/var/lib/machines/</filename> with the
index 7e127ef18cda9c8584c65b7ba16931badd9b10ee..17ffd493ab385b126d81e02dcf09ed1b6833a038 100644 (file)
@@ -504,13 +504,12 @@ node /org/freedesktop/login1 {
       stored on disk.</para>
 
       <para><function>AttachDevice()</function> may be used to assign a specific device to a specific
-      seat. The device is identified by its <filename>/sys</filename> path and must be eligible for seat
+      seat. The device is identified by its <filename>/sys/</filename> path and must be eligible for seat
       assignments. <function>AttachDevice()</function> takes three arguments: the seat id, the sysfs path,
       and a boolean for controlling polkit interactivity (see below). Device assignments are persistently
       stored on disk. To create a new seat, simply specify a previously unused seat id. For more information
       about the seat assignment logic see
-      <ulink url="https://www.freedesktop.org/wiki/Software/systemd/multiseat">Multi-Seat for Linux</ulink>.
-      </para>
+      <citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
       <para><function>FlushDevices()</function> removes all explicit seat assignments for devices, resetting
       all assignments to the automatic defaults. The only argument it takes is the polkit interactivity
diff --git a/man/org.freedesktop.oom1.xml b/man/org.freedesktop.oom1.xml
new file mode 100644 (file)
index 0000000..289a7b6
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" >
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="org.freedesktop.oom1" conditional='ENABLE_OOMD'
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>org.freedesktop.oom1</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>org.freedesktop.oom1</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>org.freedesktop.oom1</refname>
+    <refpurpose>The D-Bus interface of systemd-oomd</refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Introduction</title>
+
+    <para>
+    <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    is a system service which implements a userspace out-of-memory (OOM) killer. This page describes the
+    D-Bus interface.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>The Manager Object</title>
+
+    <para>The service exposes the following interfaces on the Manager object on the bus:</para>
+
+    <programlisting executable="systemd-oomd" node="/org/freedesktop/oom1" interface="org.freedesktop.oom1.Manager">
+node /org/freedesktop/oom1 {
+  interface org.freedesktop.oom1.Manager {
+    methods:
+      DumpByFileDescriptor(out h fd);
+  };
+  interface org.freedesktop.DBus.Peer { ... };
+  interface org.freedesktop.DBus.Introspectable { ... };
+  interface org.freedesktop.DBus.Properties { ... };
+};
+    </programlisting>
+
+    <!--method DumpByFileDescriptor is not documented!-->
+
+    <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.oom1.Manager"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.oom1.Manager"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="DumpByFileDescriptor()"/>
+
+    <!--End of Autogenerated section-->
+
+    <refsect2>
+      <title>Methods</title>
+
+      <para>...</para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>Versioning</title>
+
+    <para>These D-Bus interfaces follow <ulink url="http://0pointer.de/blog/projects/versioning-dbus.html">
+    the usual interface versioning guidelines</ulink>.</para>
+  </refsect1>
+</refentry>
index 5b8acbbd9ff78349d00e5d31a99e7929f9c271a9..b06155662a59fdb28e8f742b8710fea0b946137d 100644 (file)
@@ -147,6 +147,8 @@ node /org/freedesktop/resolve1 {
       readonly as DNSSECNegativeTrustAnchors = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s DNSStubListener = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ResolvConfMode = '...';
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -154,12 +156,6 @@ node /org/freedesktop/resolve1 {
 };
     </programlisting>
 
-    <!--method SetLinkDNSEx is not documented!-->
-
-    <!--method SetLinkDefaultRoute is not documented!-->
-
-    <!--method SetLinkDNSOverTLS is not documented!-->
-
     <!--method RegisterService is not documented!-->
 
     <!--method UnregisterService is not documented!-->
@@ -168,28 +164,8 @@ node /org/freedesktop/resolve1 {
 
     <!--method ResetServerFeatures is not documented!-->
 
-    <!--property LLMNR is not documented!-->
-
-    <!--property MulticastDNS is not documented!-->
-
-    <!--property DNSOverTLS is not documented!-->
-
-    <!--property DNSEx is not documented!-->
-
-    <!--property FallbackDNS is not documented!-->
-
-    <!--property FallbackDNSEx is not documented!-->
-
-    <!--property CurrentDNSServer is not documented!-->
-
-    <!--property CurrentDNSServerEx is not documented!-->
-
-    <!--property DNSSEC is not documented!-->
-
     <!--property DNSSECNegativeTrustAnchors is not documented!-->
 
-    <!--property DNSStubListener is not documented!-->
-
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.resolve1.Manager"/>
@@ -272,31 +248,35 @@ node /org/freedesktop/resolve1 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DNSStubListener"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ResolvConfMode"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
       <title>Methods</title>
 
-      <para><function>ResolveHostname()</function> takes a hostname and resolves it to one or more IP addresses.
-      As parameters it takes the Linux network interface index to execute the query on, or 0 if it may be
-      done on any suitable interface. The <varname>name</varname> parameter specifies the hostname to
-      resolve. Note that if required, IDNA conversion is applied to this name unless it is resolved via LLMNR or MulticastDNS. The <varname>family</varname> parameter
-      limits the results to a specific address family. It may be <constant>AF_INET</constant>,
-      <constant>AF_INET6</constant> or <constant>AF_UNSPEC</constant>. If <constant>AF_UNSPEC</constant> is specified (recommended), both kinds are retrieved, subject
-      to local network configuration (i.e. if no local, routable IPv6 address is found, no IPv6 address is
-      retrieved; and similarly for IPv4). A 64-bit <varname>flags</varname> field may be used to alter the
-      behaviour of the resolver operation (see below). The method returns an array of address records. Each
-      address record consists of the interface index the address belongs to, an address family as well as a
-      byte array with the actual IP address data (which either has 4 or 16 elements, depending on the address
-      family). The returned address family will be one of <constant>AF_INET</constant> or
-      <constant>AF_INET6</constant>. For IPv6, the returned address interface index should be used to
-      initialize the .sin6_scope_id field of a <structname>struct sockaddr_in6</structname> instance to permit
-      support for resolution to link-local IP addresses. The address array is followed by the canonical name
-      of the host, which may or may not be identical to the resolved hostname. Finally, a 64-bit
-      <varname>flags</varname> field is returned that is defined similarly to the <varname>flags</varname>
-      field that was passed in, but contains information about the resolved data (see below). If the hostname
-      passed in is an IPv4 or IPv6 address formatted as string, it is parsed, and the result is returned. In
-      this case, no network communication is done.</para>
+      <para><function>ResolveHostname()</function> takes a hostname and resolves it to one or more IP
+      addresses.  As parameters it takes the Linux network interface index to execute the query on, or 0 if
+      it may be done on any suitable interface. The <varname>name</varname> parameter specifies the hostname
+      to resolve. Note that if required, IDNA conversion is applied to this name unless it is resolved via
+      LLMNR or MulticastDNS. The <varname>family</varname> parameter limits the results to a specific address
+      family. It may be <constant>AF_INET</constant>, <constant>AF_INET6</constant> or
+      <constant>AF_UNSPEC</constant>. If <constant>AF_UNSPEC</constant> is specified (recommended), both
+      kinds are retrieved, subject to local network configuration (i.e. if no local, routable IPv6 address is
+      found, no IPv6 address is retrieved; and similarly for IPv4). A 64-bit <varname>flags</varname> field
+      may be used to alter the behaviour of the resolver operation (see below). The method returns an array
+      of address records. Each address record consists of the interface index the address belongs to, an
+      address family as well as a byte array with the actual IP address data (which either has 4 or 16
+      elements, depending on the address family). The returned address family will be one of
+      <constant>AF_INET</constant> or <constant>AF_INET6</constant>. For IPv6, the returned address interface
+      index should be used to initialize the .sin6_scope_id field of a
+      <structname>struct sockaddr_in6</structname> instance to permit support for resolution to link-local IP
+      addresses. The address array is followed by the canonical name of the host, which may or may not be
+      identical to the resolved hostname. Finally, a 64-bit <varname>flags</varname> field is returned that
+      is defined similarly to the <varname>flags</varname> field that was passed in, but contains information
+      about the resolved data (see below). If the hostname passed in is an IPv4 or IPv6 address formatted as
+      string, it is parsed, and the result is returned. In this case, no network communication is
+      done.</para>
 
       <para><function>ResolveAddress()</function> executes the reverse operation: it takes an IP address and
       acquires one or more hostnames for it. As parameters it takes the interface index to execute the query
@@ -383,15 +363,19 @@ node /org/freedesktop/resolve1 {
       <constant>AF_INET6</constant>), followed by a 4-byte or 16-byte array with the raw address data. This
       method is a one-step shortcut for retrieving the Link object for a network interface using
       <function>GetLink()</function> (see above) and then invoking the <function>SetDNS()</function> method
-      (see below) on it.
+      (see below) on it.</para>
+
+      <para><function>SetLinkDNSEx()</function> is similar to <function>SetLinkDNS()</function>, but allows
+      an IP port (instead of the default 53) and DNS name to be specified for each DNS server. The server
+      name is used for Server Name Indication (SNI), which is useful when DNS-over-TLS is
+      used. C.f. <varname>DNS=</varname> in
+      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
       </para>
 
-      <para>Network management software integrating with <filename>systemd-resolved</filename> should
-      call this method (and the five below) after the interface appeared in the kernel (and thus after a
-      network interface index has been assigned), but before the network interfaces is activated
-      (<constant>IFF_UP</constant> set) so that all settings take effect during the full time the network
-      interface is up. It is safe to alter settings while the interface is up, however. Use
-      <function>RevertLink()</function> (described below) to reset all per-interface settings.</para>
+      <para><function>SetLinkDefaultRoute()</function> specifies whether the link shall be used as the
+      default route for name queries. See the description of name routing in
+      <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      for details.</para>
 
       <para>The <function>SetLinkDomains()</function> method sets the search and routing domains to use on a
       specific network interface for DNS look-ups. It takes a network interface index and an array of domains,
@@ -428,8 +412,22 @@ node /org/freedesktop/resolve1 {
       Negative Trust Anchors (NTAs) for a specific network interface. It takes a network interface index and a
       list of domains as arguments.</para>
 
-      <para>The <function>RevertLink()</function> method may be used to revert all per-link settings done with
-      the six methods described above to the defaults again.</para>
+      <para>The <function>SetLinkDNSOverTLS()</function> method enables or disables DNS-over-TLS.
+      C.f. <varname>DNSOverTLS=</varname> in
+      <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      for details.</para>
+
+      <para>Network management software integrating with <filename>systemd-resolved</filename> should call
+      <function>SetLinkDNS()</function> or <function>SetLinkDNSEx()</function>,
+      <function>SetLinkDefaultRoute()</function>, <function>SetLinkDomains()</function> and others after the
+      interface appeared in the kernel (and thus after a network interface index has been assigned), but
+      before the network interfaces is activated (<constant>IFF_UP</constant> set) so that all settings take
+      effect during the full time the network interface is up. It is safe to alter settings while the
+      interface is up, however. Use <function>RevertLink()</function> (described below) to reset all
+      per-interface settings.</para>
+
+      <para>The <function>RevertLink()</function> method may be used to revert all per-link settings
+      described above to the defaults.</para>
 
       <refsect3>
         <title>The Flags Parameter</title>
@@ -454,11 +452,11 @@ node /org/freedesktop/resolve1 {
         classic unicast DNS, LLMNR via IPv4/UDP and IPv6/UDP respectively, as well as MulticastDNS via
         IPv4/UDP and IPv6/UDP. If all of these five bits are off on input (which is strongly recommended) the
         look-up will be done via all suitable protocols for the specific look-up. Note that these flags
-        operate as filter only, but cannot force a look-up to be done via a protocol. Specifically, <filename>systemd-resolved</filename>
-        will only route look-ups within the .local TLD to MulticastDNS (plus some reverse look-up address
-        domains), and single-label names to LLMNR (plus some reverse address lookup domains). It will route
-        neither of these to Unicast DNS servers. Also, it will do LLMNR and Multicast DNS only on interfaces
-        suitable for multicast.</para>
+        operate as filter only, but cannot force a look-up to be done via a protocol. Specifically,
+        <filename>systemd-resolved</filename> will only route look-ups within the .local TLD to MulticastDNS
+        (plus some reverse look-up address domains), and single-label names to LLMNR (plus some reverse
+        address lookup domains). It will route neither of these to Unicast DNS servers. Also, it will do
+        LLMNR and Multicast DNS only on interfaces suitable for multicast.</para>
 
         <para>On output, these five flags indicate which protocol was used to execute the operation, and hence
         where the data was found.</para>
@@ -494,34 +492,50 @@ node /org/freedesktop/resolve1 {
         the data is "rightfully" unauthenticated (which includes cases where the underlying protocol or server
         does not support authenticating data).</para>
       </refsect3>
-
-  </refsect2>
+    </refsect2>
 
     <refsect2>
       <title>Properties</title>
 
+      <para>The <varname>LLMNR</varname> and <varname>MulticastDNS</varname> properties report whether LLMNR
+      and MulticastDNS are (globally) enabled. Each may be one of <literal>yes</literal>,
+      <literal>no</literal>, and <literal>resolve</literal>. See <function>SetLinkLLMNR()</function>
+      and <function>SetLinkMulticastDNS()</function> above.</para>
+
       <para><varname>LLMNRHostname</varname> contains the hostname currently exposed on the network via
       LLMNR. It usually follows the system hostname as may be queried via
       <citerefentry project="man-pages"><refentrytitle>gethostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       but may differ if a conflict is detected on the network.</para>
 
-      <para><varname>DNS</varname> contains an array of all DNS servers currently used by
-      <filename>systemd-resolved</filename>. It contains similar information as the DNS server data written to
-      /run/systemd/resolve/resolv.conf. Each structure in the array consists of a numeric network interface
-      index, an address family, and a byte array containing the DNS server address (either 4 bytes in length
-      for IPv4 or 16 bytes in lengths for IPv6). The array contains DNS servers configured system-wide,
-      including those possibly read from a foreign <filename>/etc/resolv.conf</filename> or the
-      <varname>DNS=</varname> setting in <filename>/etc/systemd/resolved.conf</filename>, as well as
-      per-interface DNS server information either retrieved from
+      <para><varname>DNS</varname> and <varname>DNSEx</varname> contain arrays of all DNS servers currently
+      used by <filename>systemd-resolved</filename>. <varname>DNS</varname> contains information similar to
+      the DNS server data in <filename>/run/systemd/resolve/resolv.conf</filename>. Each structure in the
+      array consists of a numeric network interface index, an address family, and a byte array containing the
+      DNS server address (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
+      <varname>DNSEx</varname> is similar, but additionally contains the IP port and server name (used for
+      Server Name Indication, SNI). Both arrays contain DNS servers configured system-wide, including those
+      possibly read from a foreign <filename>/etc/resolv.conf</filename> or the <varname>DNS=</varname>
+      setting in <filename>/etc/systemd/resolved.conf</filename>, as well as per-interface DNS server
+      information either retrieved from
       <citerefentry><refentrytitle>systemd-networkd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-      or configured by external software via <function>SetLinkDNS()</function> (see above). The network
-      interface index will be 0 for the system-wide configured services and non-zero for the per-link
-      servers.</para>
+      or configured by external software via <function>SetLinkDNS()</function> or
+      <function>SetLinkDNSEx()</function> (see above). The network interface index will be 0 for the
+      system-wide configured services and non-zero for the per-link servers.</para>
+
+      <para><varname>FallbackDNS</varname> and <varname>FallbackDNSEx</varname> contain arrays of all DNS
+      servers configured as fallback servers, if any, using the same format as <varname>DNS</varname> and
+      <varname>DNSEx</varname> described above. See the description of <varname>FallbackDNS=</varname> in
+      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+      the description of when those servers are used.</para>
+
+      <para><varname>CurrentDNSServer</varname> and <varname>CurrentDNSServerEx</varname> specify the server
+      that is currently used for query resolution, in the same format as a single entry in the
+      <varname>DNS</varname> and <varname>DNSEx</varname> arrays described above.</para>
 
-      <para>Similarly, the <varname>Domains</varname> property contains an array of all search and
-      routing domains currently used by <filename>systemd-resolved</filename>. Each entry consists of a network interface index (again, 0
-      encodes system-wide entries), the actual domain name, and whether the entry is used only for routing
-      (true) or for both routing and searching (false).</para>
+      <para>Similarly, the <varname>Domains</varname> property contains an array of all search and routing
+      domains currently used by <filename>systemd-resolved</filename>. Each entry consists of a network
+      interface index (again, 0 encodes system-wide entries), the actual domain name, and whether the entry
+      is used only for routing (true) or for both routing and searching (false).</para>
 
       <para>The <varname>TransactionStatistics</varname> property contains information about the number of
       transactions <filename>systemd-resolved</filename> has processed. It contains a pair of unsigned 64-bit counters, the first
@@ -536,7 +550,14 @@ node /org/freedesktop/resolve1 {
       operations so far. It exposes three 64-bit counters: the first being the total number of current cache
       entries (both positive and negative), the second the number of cache hits, and the third the number of
       cache misses. The latter counters may be reset using <function>ResetStatistics()</function> (see
-      above). </para>
+      above).</para>
+
+      <para>The <varname>DNSSEC</varname> property specifies current status of DNSSEC validation. It is one
+      of <literal>yes</literal> (validation is enforced), <literal>no</literal> (no validation is done),
+      <literal>allow-downgrade</literal> (validation is done if the current DNS server supports it). See the
+      description of <varname>DNSSEC=</varname> in
+      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+      </para>
 
       <para>The <varname>DNSSECStatistics</varname> property contains information about the DNSSEC
       validations executed so far. It contains four 64-bit counters: the number of secure, insecure, bogus,
@@ -555,9 +576,20 @@ node /org/freedesktop/resolve1 {
       DNSSEC is supported by DNS servers until it verifies that this is not the case. Thus, the reported
       value may initially be true, until the first transactions are executed.</para>
 
-      <para>The <varname>LogLevel</varname> property shows the (maximum) log level of the manager, with the
-      same values as the <option>--log-level=</option> option described in
-      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
+      <para>The <varname>DNSOverTLS</varname> boolean property reports whether DNS-over-TLS is enabled.
+      </para>
+
+      <para>The <varname>ResolvConfMode</varname> property exposes how <filename>/etc/resolv.conf</filename>
+      is managed on the host. Currently, the values <literal>uplink</literal>, <literal>stub</literal>,
+      <literal>static</literal> (these three correspond to the three different files
+      <filename>systemd-resolved.service</filename> provides), <literal>foreign</literal> (the file is
+      managed by admin or another service, <filename>systemd-resolved.service</filename> just consumes it),
+      <literal>missing</literal> (<filename>/etc/resolv.conf</filename> is missing).</para>
+
+      <para>The <varname>DNSStubListener</varname> property reports whether the stub listener on port 53 is
+      enabled. Possible values are <literal>yes</literal> (enabled), <literal>no</literal> (disabled),
+      <literal>udp</literal> (only the UDP listener is enabled), and <literal>tcp</literal> (only the TCP
+      listener is enabled).</para>
     </refsect2>
   </refsect1>
 
@@ -612,40 +644,6 @@ node /org/freedesktop/resolve1/link/_1 {
 };
     </programlisting>
 
-    <!--method SetDNSEx is not documented!-->
-
-    <!--method SetDomains is not documented!-->
-
-    <!--method SetDefaultRoute is not documented!-->
-
-    <!--method SetLLMNR is not documented!-->
-
-    <!--method SetMulticastDNS is not documented!-->
-
-    <!--method SetDNSOverTLS is not documented!-->
-
-    <!--method SetDNSSEC is not documented!-->
-
-    <!--method SetDNSSECNegativeTrustAnchors is not documented!-->
-
-    <!--method Revert is not documented!-->
-
-    <!--property DNSEx is not documented!-->
-
-    <!--property CurrentDNSServer is not documented!-->
-
-    <!--property CurrentDNSServerEx is not documented!-->
-
-    <!--property DefaultRoute is not documented!-->
-
-    <!--property LLMNR is not documented!-->
-
-    <!--property MulticastDNS is not documented!-->
-
-    <!--property DNSOverTLS is not documented!-->
-
-    <!--property DNSSEC is not documented!-->
-
     <!--property DNSSECNegativeTrustAnchors is not documented!-->
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
@@ -714,8 +712,13 @@ node /org/freedesktop/resolve1/link/_1 {
       <function>SetLinkDNS()</function> on the Manager object, the main difference being that the later
       expects an interface index to be specified. Invoking the methods on the Manager interface has the
       benefit of reducing roundtrips, as it is not necessary to first request the Link object path via
-      <function>GetLink()</function> before invoking the methods. For further details on these methods see
-      the <interfacename>Manager</interfacename> documentation above.</para>
+      <function>GetLink()</function> before invoking the methods. The same relationship holds for
+      <function>SetDNSEx()</function>, <function>SetDomains()</function>,
+      <function>SetDefaultRoute()</function>, <function>SetLLMNR()</function>,
+      <function>SetMulticastDNS()</function>, <function>SetDNSOverTLS()</function>,
+      <function>SetDNSSEC()</function>, <function>SetDNSSECNegativeTrustAnchors()</function>, and
+      <function>Revert()</function>. For further details on these methods see the
+      <interfacename>Manager</interfacename> documentation above.</para>
     </refsect2>
 
     <refsect2>
@@ -737,8 +740,12 @@ node /org/freedesktop/resolve1/link/_1 {
       assumed available until it is detected that the configured server does not actually support it. Thus,
       this property may initially report that DNSSEC is supported on an interface.</para>
 
+      <para><varname>DefaultRoute</varname> exposes a boolean field that indicates whether the interface will
+      be used as default route for name queries. See <function>SetLinkDefaultRoute()</function> above.</para>
+
       <para>The other properties reflect the state of the various configuration settings for the link which
-      may be set with the various methods calls such as SetDNS() or SetLLMNR().</para>
+      may be set with the various methods calls such as <function>SetDNS()</function> or
+      <function>SetLLMNR()</function>.</para>
     </refsect2>
   </refsect1>
 
index 8e326617bf6d7c2d4e0ebf5a42a92ae03ef0a8fe..3c0e5b6eb14712344192c3628f217a97612fd0ab 100644 (file)
@@ -1288,11 +1288,11 @@ node /org/freedesktop/systemd1 {
       file.</para>
 
       <para><function>EnableUnitFiles()</function> may be used to enable one or more units in the system (by
-      creating symlinks to them in <filename>/etc</filename> or <filename>/run</filename>). It takes a list
+      creating symlinks to them in <filename>/etc/</filename> or <filename>/run/</filename>). It takes a list
       of unit files to enable (either just file names or full absolute paths if the unit files are residing
       outside the usual unit search paths) and two booleans: the first controls whether the unit shall be
-      enabled for runtime only (true, <filename>/run</filename>), or persistently (false,
-      <filename>/etc</filename>). The second one controls whether symlinks pointing to other units shall be
+      enabled for runtime only (true, <filename>/run/</filename>), or persistently (false,
+      <filename>/etc/</filename>). The second one controls whether symlinks pointing to other units shall be
       replaced if necessary. This method returns one boolean and an array of the changes made. The boolean
       signals whether the unit files contained any enablement information (i.e. an [Install]) section. The
       changes array consists of structures with three strings: the type of the change (one of
@@ -1301,7 +1301,7 @@ node /org/freedesktop/systemd1 {
       format.</para>
 
       <para>Similarly, <function>DisableUnitFiles()</function> disables one or more units in the system,
-      i.e. removes all symlinks to them in <filename>/etc</filename> and <filename>/run</filename>.</para>
+      i.e. removes all symlinks to them in <filename>/etc/</filename> and <filename>/run/</filename>.</para>
 
       <para>The <function>EnableUnitFilesWithFlags()</function> and <function>DisableUnitFilesWithFlags()</function>
       take in options as flags instead of booleans to allow for extendability, defined as follows:</para>
@@ -1425,7 +1425,7 @@ node /org/freedesktop/systemd1 {
       flag. Taints may be used to lower the chance of bogus bug reports. The following taints are currently
       known: <literal>split-usr</literal>, <literal>mtab-not-symlink</literal>,
       <literal>cgroups-missing</literal>, <literal>local-hwclock</literal>. <literal>split-usr</literal> is
-      set if <filename>/usr</filename> is not pre-mounted when systemd is first invoked. See
+      set if <filename>/usr/</filename> is not pre-mounted when systemd is first invoked. See
       <ulink url="http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken">
       Booting Without /usr is Broken</ulink>
       for details why this is bad. <literal>mtab-not-symlink</literal> indicates that
@@ -2094,11 +2094,11 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       <literal>disabled</literal>, and <literal>invalid</literal>. <literal>enabled</literal> indicates that a
       unit file is permanently enabled. <literal>enable-runtime</literal> indicates the unit file is only
       temporarily enabled and will no longer be enabled after a reboot (that means, it is enabled via
-      <filename>/run</filename> symlinks, rather than <filename>/etc</filename>). <literal>linked</literal>
-      indicates that a unit is linked into <filename>/etc</filename> permanently. <literal>linked-runtime</literal>
-      indicates that a unit is linked into <filename>/run</filename> temporarily (until the next
+      <filename>/run/</filename> symlinks, rather than <filename>/etc/</filename>). <literal>linked</literal>
+      indicates that a unit is linked into <filename>/etc/</filename> permanently. <literal>linked-runtime</literal>
+      indicates that a unit is linked into <filename>/run/</filename> temporarily (until the next
       reboot). <literal>masked</literal> indicates that the unit file is masked permanently.
-      <literal>masked-runtime</literal> indicates that it is masked in <filename>/run</filename> temporarily
+      <literal>masked-runtime</literal> indicates that it is masked in <filename>/run/</filename> temporarily
       (until the next reboot). <literal>static</literal> indicates that the unit is statically enabled, i.e.
       always enabled and doesn't need to be enabled explicitly. <literal>invalid</literal> indicates that it
       could not be determined whether the unit file is enabled.</para>
@@ -2414,6 +2414,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -2928,6 +2934,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -3478,6 +3490,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -4121,6 +4139,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -4661,6 +4685,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -5211,6 +5241,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -5780,6 +5816,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -6250,6 +6292,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -6720,6 +6768,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -7404,6 +7458,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -7860,6 +7920,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -8316,6 +8382,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -8859,6 +8931,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -8989,6 +9067,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
@@ -9123,6 +9207,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -9276,6 +9366,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
       readonly as IPEgressFilterPath = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as DisableControllers = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMSwap = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressure = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -9422,6 +9518,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--property DisableControllers is not documented!-->
 
+    <!--property ManagedOOMSwap is not documented!-->
+
+    <!--property ManagedOOMMemoryPressure is not documented!-->
+
+    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -9582,6 +9684,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DisableControllers"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMSwap"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPercent"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
index a2164436c37502a5ddb8b2fa9040ae8bd10b0590..cd5b5bf1589a0a1e75b5f8f06eaf9c5f972e7843 100644 (file)
@@ -59,7 +59,7 @@
     <filename>/etc/os-release</filename> should be a relative symlink
     to <filename>/usr/lib/os-release</filename>, to provide
     compatibility with applications only looking at
-    <filename>/etc</filename>. A relative symlink instead of an
+    <filename>/etc/</filename>. A relative symlink instead of an
     absolute symlink is necessary to avoid breaking the link in a
     chroot or initrd environment such as dracut.</para>
 
index 962429683d6b38fcbe3424713f575c0c798a1143..d24c010e2ce49564ee7457bf17446cf7fc2f2074 100644 (file)
         <command>attach</command> command above, and removes the unit file copies, drop-ins and image symlink
         again. This command expects an image name or path as parameter. Note that if a path is specified only the last
         component of it (i.e. the file or directory name itself, not the path to it) is used for finding matching unit
-        files. This is a convencience feature to allow all arguments passed as <command>attach</command> also to
+        files. This is a convenience feature to allow all arguments passed as <command>attach</command> also to
         <command>detach</command>.</para></listitem>
 
         <para>If <option>--now</option> and/or <option>--enable</option> are passed, the portable service(s) are
index c702d88f74d27c1be8be55cbfe19ca2227097a45..cc3c2ef5e3b7b3ea42c95270abe7cb8cc598d7c2 100644 (file)
@@ -45,6 +45,8 @@ manpages = [
  ['nss-mymachines', '8', ['libnss_mymachines.so.2'], 'ENABLE_NSS_MYMACHINES'],
  ['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_NSS_RESOLVE'],
  ['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'],
+ ['oomctl', '1', [], 'ENABLE_OOMD'],
+ ['oomd.conf', '5', ['oomd.conf.d'], 'ENABLE_OOMD'],
  ['org.freedesktop.LogControl1', '5', [], ''],
  ['org.freedesktop.home1', '5', [], 'ENABLE_HOMED'],
  ['org.freedesktop.hostname1', '5', [], 'ENABLE_HOSTNAMED'],
@@ -52,6 +54,7 @@ manpages = [
  ['org.freedesktop.locale1', '5', [], 'ENABLE_LOCALED'],
  ['org.freedesktop.login1', '5', [], 'ENABLE_LOGIND'],
  ['org.freedesktop.machine1', '5', [], 'ENABLE_MACHINED'],
+ ['org.freedesktop.oom1', '5', [], 'ENABLE_OOMD'],
  ['org.freedesktop.resolve1', '5', [], 'ENABLE_RESOLVE'],
  ['org.freedesktop.systemd1', '5', [], ''],
  ['org.freedesktop.timedate1', '5', [], 'ENABLE_TIMEDATED'],
@@ -564,6 +567,10 @@ manpages = [
    'SD_EVENT_ONESHOT',
    'sd_event_source_get_enabled'],
   ''],
+ ['sd_event_source_set_exit_on_failure',
+  '3',
+  ['sd_event_source_get_exit_on_failure'],
+  ''],
  ['sd_event_source_set_floating', '3', ['sd_event_source_get_floating'], ''],
  ['sd_event_source_set_prepare', '3', [], ''],
  ['sd_event_source_set_priority',
@@ -903,6 +910,7 @@ manpages = [
  ['systemd-networkd.service', '8', ['systemd-networkd'], 'ENABLE_NETWORKD'],
  ['systemd-notify', '1', [], ''],
  ['systemd-nspawn', '1', [], ''],
+ ['systemd-oomd.service', '8', ['systemd-oomd'], 'ENABLE_OOMD'],
  ['systemd-path', '1', [], ''],
  ['systemd-portabled.service', '8', ['systemd-portabled'], 'ENABLE_PORTABLED'],
  ['systemd-pstore.service', '8', ['systemd-pstore'], 'ENABLE_PSTORE'],
@@ -1036,12 +1044,14 @@ manpages = [
   ''],
  ['udev_device_has_tag',
   '3',
-  ['udev_device_get_devlinks_list_entry',
+  ['udev_device_get_current_tags_list_entry',
+   'udev_device_get_devlinks_list_entry',
    'udev_device_get_properties_list_entry',
    'udev_device_get_property_value',
    'udev_device_get_sysattr_list_entry',
    'udev_device_get_sysattr_value',
    'udev_device_get_tags_list_entry',
+   'udev_device_has_current_tag',
    'udev_device_set_sysattr_value'],
   ''],
  ['udev_device_new_from_syspath',
index ecc6e28a84a021568c5d1a49ba8b4025eb600bd1..f39be20fc51d626c558629e9d534932f57eea057 100644 (file)
@@ -46,8 +46,8 @@
     systemd-logind, instead.</para>
 
     <para>These functions synchronously access data in
-    <filename>/proc</filename>, <filename>/sys/fs/cgroup</filename>
-    and <filename>/run</filename>. All of these are virtual file
+    <filename>/proc/</filename>, <filename>/sys/fs/cgroup/</filename>
+    and <filename>/run/</filename>. All of these are virtual file
     systems, hence the runtime cost of the accesses is relatively
     cheap.</para>
 
 
     <para>
       <ulink url="https://www.freedesktop.org/wiki/Software/systemd/multiseat">Multi-Seat on Linux</ulink>
-      for an introduction to multi-seat support on Linux and the background for this set of APIs.
+      may also be of historical interest.
     </para>
   </refsect1>
-
 </refentry>
index f5ee01ca3537cb347bb341c6d94b357ea207522c..d1a168a23b7d368d291f9ffce5e28ef2dbc8e6d5 100644 (file)
     for the credential fields that could not be determined atomically
     at peer connection time, and which were later added by reading
     augmenting credential data from
-    <filename>/proc</filename>. Similarly, for credential objects
+    <filename>/proc/</filename>. Similarly, for credential objects
     retrieved via <function>sd_bus_get_owner_creds()</function>, the
     mask is set for the fields that could not be determined atomically
     at bus creation time, but have been augmented. Similarly, for
 
     <para><function>sd_bus_creds_get_augmented_mask()</function>
     returns the mask of fields that have been augmented from data in
-    <filename>/proc</filename>, and are thus not suitable for
+    <filename>/proc/</filename>, and are thus not suitable for
     authorization decisions.</para>
 
     <para><function>sd_bus_creds_ref()</function> always returns the
index 8532c2bf466c85c8c915434172146ce067b6af58..c21876834642d2b29bda022dc68808135d2d4a47 100644 (file)
     is equivalent to <function>sd_bus_open()</function>. This description string is used in log
     messages about the bus object, and including a "name" for the bus makes them easier to
     understand. Some messages are emitted during bus initialization, hence using this function is
-    prefereable to setting the description later with
+    preferable to setting the description later with
     <function>sd_bus_open_with_description()</function>. The argument is copied internally and will
     not be referenced after the function returns.</para>
 
       <para>Returned errors may indicate the following problems:</para>
 
       <variablelist>
-
         <varlistentry>
           <term><constant>-EINVAL</constant></term>
 
           <listitem><para>The specified parameters are invalid.</para></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><constant>-ENOMEDIUM</constant></term>
+
+          <listitem><para>The requested bus type is not available because of invalid environment (for example
+          the user session bus is not available because <varname>$XDG_RUNTIME_DIR</varname> is not set).
+          </para></listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><constant>-ENOMEM</constant></term>
 
index 7f9f9703b63c2a550dea320c6f5eaccb66e8c1da..9bac0246c8458b568521b169b97211efc6a8c0a3 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_message_read_array()</function> gives access to an element array in
-    message <parameter>m</parameter>. The "read pointer" in the message must be right before an
-    array of type <parameter>type</parameter>. As a special case, <parameter>type</parameter> may be
-    <constant>NUL</constant>, in which case any type is acceptable. A pointer to the array data is
-    returned in the parameter <parameter>ptr</parameter> and the size of array data (in bytes) is
-    returned in the parameter <parameter>size</parameter>. If <parameter>size</parameter> is 0, a
-    valid non-null pointer will be returned, but it may not be dereferenced. The data is aligned as
-    appropriate for the data type. The data is part of the message — it may not be modified and is
-    valid only as long as the message is referenced. After this function returns, the "read pointer"
-    points at the next element after the array.</para>
+    <para><function>sd_bus_message_read_array()</function> provides access to an array elements in the
+    bus message <parameter>m</parameter>. The "read pointer" in the message must be right before an array of type
+    <parameter>type</parameter>. As a special case, <parameter>type</parameter> may be
+    <constant>NUL</constant>, in which case any trivial type is acceptable. A pointer to the array data is returned
+    in the parameter <parameter>ptr</parameter> and the size of array data (in bytes) is returned in the
+    parameter <parameter>size</parameter>. If the returned <parameter>size</parameter> parameter is 0, a
+    valid non-null pointer will be returned as <parameter>ptr</parameter>, but it may not be
+    dereferenced. The data is aligned as appropriate for the data type. The data is part of the message — it
+    may not be modified and is valid only as long as the message is referenced. After this function returns,
+    the "read pointer" points at the next element after the array.</para>
 
     <para>Note that this function only supports arrays of trivial types, i.e. arrays of booleans, the various
     integer types, as well as floating point numbers. In particular it may not be used for arrays of strings,
     <title>Return Value</title>
 
     <para>
-      On success, <function>sd_bus_message_read_array()</function> returns 0 or
-      a positive integer. On failure, it returns a negative errno-style error
-      code.
+      On success and when an array was read, <function>sd_bus_message_read_array()</function> returns an
+      integer greater than zero. If invoked while inside a container element (such as an array, e.g. when
+      operating on an array of arrays) and the final element of the outer container has been read already and
+      the read pointer is thus behind the last element of the outer container this call returns 0 (and the
+      returned pointer will be <constant>NULL</constant> and the size will be 0). On failure, it returns a
+      negative errno-style error code.
     </para>
 
     <refsect2>
index 2cdf436db2bc981857f798cbbd3e4c45322f9ce6..233dd7c4fa69293186f5ce6d9159da222c09f6c0 100644 (file)
     single receiver). It's behavior is similar to calling
     <citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     followed by calling <function>sd_bus_send()</function>.</para>
+
+    <para><function>sd_bus_send()</function>/<function>sd_bus_send_to()</function> will write the message
+    directly to the underlying transport (e.g. kernel socket buffer) if possible. If the connection is not
+    set up fully yet the message is queued locally. If the transport buffers are congested any unwritten
+    message data is queued locally, too. If the connection has been closed or is currently being closed the
+    call fails.
+    <citerefentry><refentrytitle>sd_bus_process</refentrytitle><manvolnum>3</manvolnum></citerefentry> should
+    be invoked to write out any queued message data to the transport.</para>
   </refsect1>
 
   <refsect1>
       <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_process</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 1db536ff2ad133a5021626d7c483533c99aa9cfb..74ebe6d2641a5edb9e7ff085c38cb36d8599723c 100644 (file)
     <citerefentry
     project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
 
-    <para>If the second parameter of
-    <function>sd_event_add_child()</function> is passed as NULL no
-    reference to the event source object is returned. In this case the
-    event source is considered "floating", and will be destroyed
-    implicitly when the event loop itself is destroyed.</para>
+    <para>If the second parameter of <function>sd_event_add_child()</function> is passed as
+    <constant>NULL</constant> no reference to the event source object is returned. In this case the event
+    source is considered "floating", and will be destroyed implicitly when the event loop itself is
+    destroyed.</para>
 
     <para>Note that the <parameter>handler</parameter> function is
     invoked at a time where the child process is not reaped yet (and
     event sources are installed will not be reaped by the event loop
     implementation.</para>
 
+    <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_child()</function> is
+    <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+    event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+    the exit code parameter to
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
     <para>If both a child process state change event source and a
     <constant>SIGCHLD</constant> signal event source is installed in
     the same event loop, the configured event source priorities decide
index 92be8353e647d08584f7c6d8de9b62712401dbb2..d1d6d980ee9d04fd3ae70f94229a73e4a9a86e66 100644 (file)
     <constant>SD_EVENT_OFF</constant> with
     <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
-    <para>If the second parameter of these functions is passed as
-    NULL no reference to the event source object is returned. In this
-    case the event source is considered "floating", and will be
-    destroyed implicitly when the event loop itself is
-    destroyed.</para>
+    <para>If the second parameter of these functions is passed as <constant>NULL</constant> no reference to
+    the event source object is returned. In this case the event source is considered "floating", and will be
+    destroyed implicitly when the event loop itself is destroyed.</para>
+
+    <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_defer()</function> or
+    <function>sd_event_add_post()</function> is <constant>NULL</constant>, and the event source fires, this
+    will be considered a request to exit the event loop. In this case, the <parameter>userdata</parameter>
+    parameter, cast to an integer, is passed as the exit code parameter to
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Similar
+    functionality is not available for <function>sd_event_add_exit()</function>, as these types of event
+    sources are only dispatched when exiting anyway.</para>
   </refsect1>
 
   <refsect1>
index 8860699db3d085dd6f8c4e7f2c16b674874d3b88..27d43853e65facf73d982c6a0959912689118516 100644 (file)
@@ -66,7 +66,7 @@
     function to call when the inode changes. The handler function will be passed the <parameter>userdata</parameter>
     pointer, which may be chosen freely by the caller. The handler also receives a pointer to a <structname>struct
     inotify_event</structname> structure containing information about the inode event. The <parameter>mask</parameter>
-    parameter specifie which types of inode events to watch specifically. It must contain an OR-ed combination of
+    parameter specifies which types of inode events to watch specifically. It must contain an OR-ed combination of
     <constant>IN_ACCESS</constant>, <constant>IN_ATTRIB</constant>, <constant>IN_CLOSE_WRITE</constant>, … flags. See
     <citerefentry project='man-pages'><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
     further information.</para>
     it with
     <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
-    <para>If the second parameter of <function>sd_event_add_inotify()</function> is passed as NULL no reference to the
-    event source object is returned. In this case the event source is considered "floating", and will be destroyed
-    implicitly when the event loop itself is destroyed.</para>
+    <para>If the second parameter of <function>sd_event_add_inotify()</function> is passed as
+    <constant>NULL</constant> no reference to the event source object is returned. In this case the event
+    source is considered "floating", and will be destroyed implicitly when the event loop itself is
+    destroyed.</para>
+
+    <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_inotify()</function> is
+    <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+    event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+    the exit code parameter to
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
     <para><function>sd_event_source_get_inotify_mask()</function> retrieves the configured inotify watch mask of an
     event source created previously with <function>sd_event_add_inotify()</function>. It takes the event source object
index 35d02a17000c8dac6f08ccee3f1e80ba77e6c1b2..51238f47555bb90e786af8f784d5ffa03a236831 100644 (file)
     "floating", and will be destroyed implicitly when the event loop
     itself is destroyed.</para>
 
+    <para>If the <parameter>handler</parameter> to <function>sd_event_add_io()</function> is
+    <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+    event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+    the exit code parameter to
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
     <para>Note that this call does not take possession of the file descriptor passed in, ownership (and thus
     the duty to close it when it is no longer needed) remains with the caller. However, with the
     <function>sd_event_source_set_io_fd_own()</function> call (see below) the event source may optionally
index 43794bd7ceb683cf896aa00a194d282b3bd22111..85de53120f1e57349658040d1aac2b7abda3f9b3 100644 (file)
@@ -79,9 +79,7 @@
     threads before this function is called (using <citerefentry
     project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
     <citerefentry
-    project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>). If
-    the handler is not specified (<parameter>handler</parameter> is <constant>NULL</constant>), a default
-    handler which causes the program to exit cleanly will be used.</para>
+    project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
 
     <para>By default, the event source is enabled permanently
     (<constant>SD_EVENT_ON</constant>), but this may be changed with
     "floating", and will be destroyed implicitly when the event loop
     itself is destroyed.</para>
 
+    <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_signal()</function> is
+    <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+    event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+    the exit code parameter to
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
     <para><function>sd_event_source_get_signal()</function> returns
     the configured signal number of an event source created previously
     with <function>sd_event_add_signal()</function>. It takes the
index 1fc24c8ab07994a42f295926049cefcd28638811..24a316f9edd7b6317e70dd7ee47d4f4f729458d8 100644 (file)
     "floating", and will be destroyed implicitly when the event loop
     itself is destroyed.</para>
 
-    <para>If the <parameter>handler</parameter> to
-    <function>sd_event_add_time()</function> is
-    <constant>NULL</constant>, and the event source fires, this will
-    be considered a request to exit the event loop. In this case, the
-    <parameter>userdata</parameter> parameter, cast to an integer, is
-    used for the exit code passed to
+    <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_time()</function> is
+    <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+    event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+    the exit code parameter to
     <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
     <para>Use <constant>CLOCK_BOOTTIME_ALARM</constant> and
index a02897af0b3a7cca679aae34abac9c3640503b06..53aed7001267a89ea5f366d53c8354b856d1c38e 100644 (file)
     conflict with regular exit codes returned by
     <function>sd_event_loop()</function>, if these exit codes shall be
     distinguishable.</para>
+
+    <para>Note that for most event source types passing the callback pointer as <constant>NULL</constant> in
+    the respective constructor call (i.e. in
+    <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+    …) has the effect of <function>sd_event_exit()</function> being invoked once the event source triggers,
+    with the specified userdata pointer cast to an integer as the exit code parameter. This is useful to
+    automatically terminate an event loop after some condition, such as a time-out or reception of
+    <constant>SIGTERM</constant> or similar. See the documentation for the respective constructor call for
+    details.</para>
   </refsect1>
 
   <refsect1>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 
diff --git a/man/sd_event_source_set_exit_on_failure.xml b/man/sd_event_source_set_exit_on_failure.xml
new file mode 100644 (file)
index 0000000..f9d8748
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_event_source_set_exit_on_failure" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_event_source_set_exit_on_failure</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_event_source_set_exit_on_failure</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_event_source_set_exit_on_failure</refname>
+    <refname>sd_event_source_get_exit_on_failure</refname>
+
+    <refpurpose>Set or retrieve the exit-on-failure feature of event sources</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-event.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_event_source_set_exit_on_failure</function></funcdef>
+        <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
+        <paramdef>int <parameter>b</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_event_source_get_exit_on_failure</function></funcdef>
+        <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
+      </funcprototype>
+
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_event_source_set_exit_on_failure()</function> may be used to set/unset the
+    exit-on-failure flag of the event source object specified as <parameter>source</parameter>. The flag
+    defaults to off. If on and the callback function set for the event source returns a failure code (i.e. a
+    negative value) the event loop is exited too, using the callback return code as the exit code for
+    <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If
+    off, the event source is disabled but the event loop continues to run. Setting this flag is useful for
+    "dominant" event sources that define the purpose and reason for the event loop, and whose failure hence
+    should propagate to the event loop itself — as opposed to "auxiliary" event sources whose failures should
+    remain local and affect the event source, but not propagate further.</para>
+
+    <para><function>sd_event_source_get_exit_on_failure()</function> may be used to query the flag currently
+    set for the event source object <parameter>source</parameter>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, <function>sd_event_source_set_exit_on_failure()</function> returns a non-negative
+    integer.  <function>sd_event_source_get_exit_on_failure()</function> returns 0 if the flag is off, &gt; 0
+    if the flag is on. On failure, both return a negative errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
+
+          <listitem><para>The event source refers to an exit event source (as created with
+          <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>),
+          for which this functionality is not supported.</para></listitem>
+        </varlistentry>
+
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index 26a0db12057af994881edd7679a2d93d67f169e5..339bb327079bd071c774997bcfaee5645f704a27 100644 (file)
     <constant>NULL</constant>, it is checked whether the file
     descriptor is bound to the specified filename. Special files in
     this context are character device nodes and files in
-    <filename>/proc</filename> or <filename>/sys</filename>.</para>
+    <filename>/proc/</filename> or <filename>/sys/</filename>.</para>
   </refsect1>
 
   <refsect1>
index 87b12c4bdff8b16ac28ffb67ac00a4421e371f75..3721ed91ef83d1d3655f41f8d22eecc618795f78 100644 (file)
         <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.  This is
         useful for implementing services that can restart after an explicit request or a crash without losing
         state. Any open sockets and other file descriptors which should not be closed during the restart may be stored
-        this way. Application state can either be serialized to a file in <filename>/run</filename>, or better, stored
+        this way. Application state can either be serialized to a file in <filename>/run/</filename>, or better, stored
         in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
         file descriptor. Note that the service manager will accept messages for a service only if its
         <varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
index 9c16d5bc9c01c6841f5eebfc62727ab950af78d0..f684c03aeba4576bd69868d0fdb5350a9ab9f728 100644 (file)
     <function>sd_peer_get_cgroup()</function> calls operate similar to
     their PID counterparts, but operate on a connected AF_UNIX socket
     and retrieve information about the connected peer process. Note
-    that these fields are retrieved via <filename>/proc</filename>,
+    that these fields are retrieved via <filename>/proc/</filename>,
     and hence are not suitable for authorization purposes, as they are
     subject to races.</para>
   </refsect1>
index 3efbb6db00e84e2247cbbef9be70b858d6a68dbb..5b73043ce2d424b53ac629a33c05175bc5fdbfe7 100644 (file)
     <entry>Operating system ID</entry>
     <entry>The operating system identifier of the running system, as read from the <varname>ID=</varname> field of <filename>/etc/os-release</filename>. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
   </row>
+  <row id='T'>
+    <entry><literal>%T</literal></entry>
+    <entry>Directory for temporary files</entry>
+    <entry>This is either <filename>/tmp<!-- no / --></filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to. (Note that the directory may be specified without a trailing slash.)</entry>
+  </row>
   <row id='v'>
     <entry><literal>%v</literal></entry>
     <entry>Kernel release</entry>
     <entry>Identical to <command>uname -r</command> output.</entry>
   </row>
+  <row id='V'>
+    <entry><literal>%V</literal></entry>
+    <entry>Directory for larger and persistent temporary files</entry>
+    <entry>This is either <filename>/var/tmp<!-- no / --></filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to. (Note that the directory may be specified without a trailing slash.)</entry>
+  </row>
   <row id='w'>
     <entry><literal>%w</literal></entry>
     <entry>Operating system version ID</entry>
index 70504510f9ca6354889df72f6ab06f0cf2c4ae6e..d34879506311397165cf2bc9586bfbc98f41dd37 100644 (file)
@@ -70,11 +70,11 @@ key.pattern.overridden.with.glob = custom
     followed by <literal>=</literal>, see SYNOPSIS.</para>
 
     <para>Any access permission errors and attempts to write variables not present on the local system are
-    logged at debug level and do not cause the service to fail. Moreover, if a variable assignment is
-    prefixed with a single <literal>-</literal> character, failure to set the variable for other reasons will
-    be logged at debug level and will not cause the service to fail. In other cases, errors when setting
-    variables are logged with higher priority and cause the service to return failure at the end (after
-    processing other variables).</para>
+    logged at debug level and do not cause the service to fail. Other types of errors when setting variables
+    are logged with higher priority and cause the service to return failure at the end (after processing
+    other variables). As an exception, if a variable assignment is prefixed with a single
+    <literal>-</literal> character, failure to set the variable for any reason will be logged at debug level
+    and will not cause the service to fail.</para>
 
     <para>The settings configured with <filename>sysctl.d</filename> files will be applied early on boot. The
     network interface-specific options will also be applied individually for each network interface as it
index dc02fdcb86ec256ef31df79d408bfebbfe10559b..61f8d9c9fe30ef7a013e360b819f8ccd023d9086 100644 (file)
@@ -663,7 +663,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             directories, an additional symlink is created, linking it into the unit configuration path, thus ensuring
             it is found when requested by commands such as <command>start</command>. The file system where the linked
             unit files are located must be accessible when systemd is started (e.g. anything underneath
-            <filename>/home</filename> or <filename>/var</filename> is not allowed, unless those directories are
+            <filename>/home/</filename> or <filename>/var/</filename> is not allowed, unless those directories are
             located on the root file system).</para>
 
             <para>This command will print the file system operations executed. This output may be suppressed by passing
@@ -901,7 +901,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             <command>disable</command>. The effect of this command is that a unit file is made available for commands
             such as <command>start</command>, even though it is not installed directly in the unit search path. The
             file system where the linked unit files are located must be accessible when systemd is started
-            (e.g. anything underneath <filename>/home</filename> or <filename>/var</filename> is not allowed, unless
+            (e.g. anything underneath <filename>/home/</filename> or <filename>/var/</filename> is not allowed, unless
             those directories are located on the root file system).</para>
           </listitem>
         </varlistentry>
@@ -916,10 +916,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             <literal>foo.service.d/</literal> with all their contained files are removed, both below the persistent and
             runtime configuration directories (i.e. below <filename>/etc/systemd/system</filename> and
             <filename>/run/systemd/system</filename>); if the unit file has a vendor-supplied version (i.e. a unit file
-            located below <filename>/usr</filename>) any matching persistent or runtime unit file that overrides it is
+            located below <filename>/usr/</filename>) any matching persistent or runtime unit file that overrides it is
             removed, too. Note that if a unit file has no vendor-supplied version (i.e. is only defined below
             <filename>/etc/systemd/system</filename> or <filename>/run/systemd/system</filename>, but not in a unit
-            file stored below <filename>/usr</filename>), then it is not removed. Also, if a unit is masked, it is
+            file stored below <filename>/usr/</filename>), then it is not removed. Also, if a unit is masked, it is
             unmasked.</para>
 
             <para>Effectively, this command may be used to undo all changes made with <command>systemctl
@@ -970,7 +970,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             not already exist, new unit files will be opened for editing.</para>
 
             <para>If <option>--runtime</option> is specified, the changes will
-            be made temporarily in <filename>/run</filename> and they will be
+            be made temporarily in <filename>/run/</filename> and they will be
             lost on the next reboot.</para>
 
             <para>If the temporary file is empty upon exit, the modification of
@@ -982,8 +982,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
 
             <para>Note that this command cannot be used to remotely edit units
             and that you cannot temporarily edit units which are in
-            <filename>/etc</filename>, since they take precedence over
-            <filename>/run</filename>.</para>
+            <filename>/etc/</filename>, since they take precedence over
+            <filename>/run/</filename>.</para>
           </listitem>
         </varlistentry>
 
@@ -2100,7 +2100,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           (and related commands), make changes only temporarily, so
           that they are lost on the next reboot. This will have the
           effect that changes are not made in subdirectories of
-          <filename>/etc</filename> but in <filename>/run</filename>,
+          <filename>/etc/</filename> but in <filename>/run/</filename>,
           with identical immediate effects, however, since the latter
           is lost on reboot, the changes are lost too.</para>
 
@@ -2303,6 +2303,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
     <xi:include href="less-variables.xml" xpointer="pager"/>
     <xi:include href="less-variables.xml" xpointer="less"/>
     <xi:include href="less-variables.xml" xpointer="lesscharset"/>
+    <xi:include href="less-variables.xml" xpointer="lesssecure"/>
     <xi:include href="less-variables.xml" xpointer="colors"/>
     <xi:include href="less-variables.xml" xpointer="urlify"/>
   </refsect1>
index 8c0e8a88f9e4a54e4fcedf571b5d837250f8d0fb..ba8fe7e9280ac352355cd6d4227e90d0a0afc3b3 100644 (file)
     It is intended to be used after boot to ensure that users are
     properly notified.</para>
 
-    <para>See the <ulink
-    url="https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">
-    developer documentation</ulink> for more information about the
-    system password logic.</para>
+    <para>See the <ulink url="https://systemd.io/PASSWORD_AGENTS/">developer
+    documentation</ulink> for more information about the system password logic.
+    </para>
 
     <para>Note that these services invoke
     <citerefentry><refentrytitle>systemd-tty-ask-password-agent</refentrytitle><manvolnum>1</manvolnum></citerefentry>
index 9bb045b9439554c49cb1e98f981130fa4e1355a9..f696623ee7bee066b0690ec56bee359271b8797f 100644 (file)
@@ -81,9 +81,8 @@
     or similar.</para>
 
     <para>Additional password agents may be implemented according to
-    the <ulink
-    url="https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">systemd
-    Password Agent Specification</ulink>.</para>
+    the <ulink url="https://systemd.io/PASSWORD_AGENTS/">systemd Password Agent
+    Specification</ulink>.</para>
 
     <para>If a password is queried on a TTY, the user may press TAB to
     hide the asterisks normally shown for each character typed.
index 6181cdf8363c9e08b2e7f137d6046c611d957c09..2d209ab323d339865549d18aa8643500d5214396 100644 (file)
@@ -46,7 +46,7 @@
     file paths or are assumed in the systemd control group hierarchy.
     If no argument is specified and the current working directory is
     beneath the control group mount point
-    <filename>/sys/fs/cgroup</filename>, shows the contents of the
+    <filename>/sys/fs/cgroup/</filename>, shows the contents of the
     control group the working directory refers to. Otherwise, the full
     systemd control group hierarchy is shown.</para>
 
index 5beeb586d7c1e269751f585b5fd12d5e15027416..356ec05c776247c61ff5c1bdded20913f5aeb239 100644 (file)
         <term><option>-r</option></term>
         <term><option>--raw</option></term>
 
-        <listitem><para>Format byte counts (as in memory usage and I/O metrics)
+        <listitem><para>Format byte counts (as in memory usage and I/O metrics) and CPU time
         with raw numeric values rather than human-readable
         numbers.</para></listitem>
       </varlistentry>
index e3c17d64d8c4d1fc80b848832a2036bf5396b5cb..cb18db246b9906a2bfb3c2f73ec7a14f4b8a6c0f 100644 (file)
         LUKS device given by the UUID appear under the provided
         name.</para>
 
+        <para>This parameter is the analogue of the first <citerefentry><refentrytitle>crypttab</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> field <replaceable>volume-name</replaceable>.</para>
+
         <para><varname>rd.luks.name=</varname> is honored only by
         initial RAM disk (initrd) while <varname>luks.name=</varname>
         is honored by both the main system and the initrd.</para>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>luks.options=</varname></term>
-        <term><varname>rd.luks.options=</varname></term>
+        <term><varname>luks.data=</varname></term>
+        <term><varname>rd.luks.data=</varname></term>
 
-        <listitem><para>Takes a LUKS super block UUID followed by an
-        <literal>=</literal> and a string of options separated by
-        commas as argument. This will override the options for the
-        given UUID.</para>
-        <para>If only a list of options, without an UUID, is
-        specified, they apply to any UUIDs not specified elsewhere,
-        and without an entry in
-        <filename>/etc/crypttab</filename>.</para><para>
-        <varname>rd.luks.options=</varname> is honored only by initial
-        RAM disk (initrd) while <varname>luks.options=</varname> is
-        honored by both the main system and the initrd.</para>
+        <listitem><para>Takes a LUKS super block UUID followed by a <literal>=</literal> and a block device
+        specification for device hosting encrypted data.</para>
+
+        <para>For those entries specified with <varname>rd.luks.uuid=</varname> or
+        <varname>luks.uuid=</varname>, the data device will be set to the one specified by
+        <varname>rd.luks.data=</varname> or <varname>luks.data=</varname> of the corresponding UUID.</para>
+
+        <para>LUKS data device parameter is usefull for specifying encrypted data devices with detached headers specified in
+        <varname>luks.options</varname> entry containing <literal>header=</literal> argument. For example,
+        <varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
+        <varname>rd.luks.options=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/path/to/luks.hdr
+        <varname>rd.luks.data=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx.
+        Hence, in this case, we will attempt to unlock LUKS device assembled from data device <literal>/dev/sdx</literal>
+        and LUKS header (metadata) put in <literal>/path/to/luks.hdr</literal> file. This syntax is for now
+        only supported on a per-device basis, i.e. you have to specify LUKS device UUID.</para>
+
+        <para>This parameter is the analogue of the second <citerefentry><refentrytitle>crypttab</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> field <replaceable>encrypted-device</replaceable>.</para>
+
+        <para><varname>rd.luks.data=</varname> is honored only by initial RAM disk (initrd) while
+        <varname>luks.data=</varname> is honored by both the main system and the initrd.</para>
         </listitem>
       </varlistentry>
 
         This syntax is for now only supported on a per-device basis,
         i.e. you have to specify LUKS device UUID.</para>
 
+        <para>This parameter is the analogue of the third <citerefentry><refentrytitle>crypttab</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> field <replaceable>key-file</replaceable>.</para>
+
         <para><varname>rd.luks.key=</varname>
         is honored only by initial RAM disk
         (initrd) while
         the initrd.</para>
         </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>luks.options=</varname></term>
+        <term><varname>rd.luks.options=</varname></term>
+
+        <listitem><para>Takes a LUKS super block UUID followed by an
+        <literal>=</literal> and a string of options separated by
+        commas as argument. This will override the options for the
+        given UUID.</para>
+        <para>If only a list of options, without an UUID, is
+        specified, they apply to any UUIDs not specified elsewhere,
+        and without an entry in
+        <filename>/etc/crypttab</filename>.</para>
+
+        <para>This parameter is the analogue of the fourth <citerefentry><refentrytitle>crypttab</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> field <replaceable>options</replaceable>.</para>
+
+        <para>It is possible to specify an external device which
+        should be mounted before we attempt to unlock the LUKS device.
+        systemd-cryptsetup will assemble LUKS device by combining
+        data device specified in <varname>luks.data</varname> with
+        detached LUKS header found in <literal>header=</literal>
+        argument. For example,
+        <varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
+        <varname>rd.luks.options=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/luks.hdr:LABEL=hdrdev
+        <varname>rd.luks.data=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx.
+        Hence, in this case, we will attempt to mount file system
+        residing on the block device with label <literal>hdrdev</literal>, and look
+        for <literal>luks.hdr</literal> on that file system. Said header will be used
+        to unlock (decrypt) encrypted data stored on /dev/sdx.
+        This syntax is for now only supported on a per-device basis,
+        i.e. you have to specify LUKS device UUID.</para>
+
+        <para><varname>rd.luks.options=</varname> is honored only by initial
+        RAM disk (initrd) while <varname>luks.options=</varname> is
+        honored by both the main system and the initrd.</para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 47051b9cef307d7cc62e0ef12c17723fab538489..164fc2ed849ea225843347d933048357a0d4bd88 100644 (file)
 
     <para><filename>systemd-cryptsetup@.service</filename> will ask
     for hard disk passwords via the <ulink
-    url="https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">
-    password agent logic</ulink>, in order to query the user for the
-    password using the right mechanism at boot and during
-    runtime.</para>
+    url="https://systemd.io/PASSWORD_AGENTS/">password agent logic</ulink>, in
+    order to query the user for the password using the right mechanism at boot
+    and during runtime.</para>
 
     <para>At early boot and when the system manager configuration is reloaded, <filename>/etc/crypttab</filename> is
     translated into <filename>systemd-cryptsetup@.service</filename> units by
index 02d7b8851008487e910e00cdff6ef7b03516a7dd..381add7f0c4ff52205bc2c2b591a96a63d019082 100644 (file)
@@ -34,9 +34,9 @@
 
     <para><command>systemd-delta</command> may be used to identify and
     compare configuration files that override other configuration
-    files. Files in <filename>/etc</filename> have highest priority,
-    files in <filename>/run</filename> have the second highest
-    priority, …, files in <filename>/usr/lib</filename> have lowest
+    files. Files in <filename>/etc/</filename> have highest priority,
+    files in <filename>/run/</filename> have the second highest
+    priority, …, files in <filename>/usr/lib/</filename> have lowest
     priority. Files in a directory with higher priority override files
     with the same name in directories of lower priority. In addition,
     certain configuration files can have <literal>.d</literal>
@@ -54,8 +54,8 @@
     <para>The command line argument will be split into a prefix and a
     suffix. Either is optional. The prefix must be one of the
     directories containing configuration files
-    (<filename>/etc</filename>, <filename>/run</filename>,
-    <filename>/usr/lib</filename>, …). If it is given, only
+    (<filename>/etc/</filename>, <filename>/run/</filename>,
+    <filename>/usr/lib/</filename>, …). If it is given, only
     overriding files contained in this directory will be shown.
     Otherwise, all overriding files will be shown. The suffix must be
     a name of a subdirectory containing configuration files like
index ac5ffa56451fd766499e455581f523dbf2d57cb7..36c4602d6965159ed86e0af79caa3e4a31ca3c79 100644 (file)
@@ -62,7 +62,7 @@
         </thead>
         <tbody>
           <row>
-            <entry valign="top" morerows="12">VM</entry>
+            <entry valign="top" morerows="13">VM</entry>
             <entry><varname>qemu</varname></entry>
             <entry>QEMU software virtualization, without KVM</entry>
           </row>
             <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems), for legacy and KVM hypervisor</entry>
           </row>
 
+          <row>
+            <entry><varname>powervm</varname></entry>
+            <entry>IBM PowerVM hypervisor - comes as firmware with some IBM POWER servers</entry>
+          </row>
+
           <row>
             <entry><varname>xen</varname></entry>
             <entry>Xen hypervisor (only domU, not dom0)</entry>
           </row>
 
           <row>
-            <entry valign="top" morerows="8">Container</entry>
+            <entry valign="top" morerows="9">Container</entry>
             <entry><varname>openvz</varname></entry>
             <entry>OpenVZ/Virtuozzo</entry>
           </row>
index a2e77281c8d284a7832cadfab1ce9a748bfc72bf..1c761c4996b5121f3f6251174f792be68a0c2d68 100644 (file)
 
     <para>OS images may use any kind of Linux-supported file systems. In addition they may make use of LUKS
     disk encryption, and contain Verity integrity information. Note that qualifying OS images may be booted
-    with <citerefentry><refentrytitle>system-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+    with <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
     <option>--image=</option> switch, and be used as root file system for system service using the
     <varname>RootImage=</varname> unit file setting, see
-    <citerefentry><refentrytitle>system.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
     <para>Note that the partition table shown when invoked without command switch (as listed below) does not
     necessarily show all partitions included in the image, but just the partitions that are understood and
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>system-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>system.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>,
       <citerefentry project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>fdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>
index 0976394b662e2de92994745c0085bd0ea97c414b..e60bfa0eb0b306d27c65551e41c5523fa943f628 100644 (file)
@@ -38,7 +38,7 @@
     basic system settings interactively on the first boot, or
     optionally non-interactively when a system image is created.
     The service is started if <varname>ConditionFirstBoot=yes</varname>
-    is satisfied. This essentially means that <filename>/etc</filename>
+    is satisfied. This essentially means that <filename>/etc/</filename>
     is empty, see
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for details.</para>
       <varlistentry>
         <term><option>--prompt</option></term>
 
-        <listitem><para>Query the user for locale, keymap, timezone, hostname
-        and root password. This is equivalent to specifying
+        <listitem><para>Query the user for locale, keymap, timezone, hostname,
+        root's password, and root's shell. This is equivalent to specifying
         <option>--prompt-locale</option>,
         <option>--prompt-keymap</option>,
         <option>--prompt-timezone</option>,
index 59f18968608d74f9e30171947e35595637eec6a6..e842f3f9bc84e1a6b47a953ecbe87c9e3936b341 100644 (file)
       <varlistentry>
         <term><varname>mount.usr=</varname></term>
 
-        <listitem><para>Takes the <filename>/usr</filename> filesystem
+        <listitem><para>Takes the <filename>/usr/</filename> filesystem
         to be mounted by the initrd. If
         <varname>mount.usrfstype=</varname> or
         <varname>mount.usrflags=</varname> is set, then
         <varname>root=</varname>.</para>
 
         <para>Otherwise, this parameter defaults to the
-        <filename>/usr</filename> entry found in
+        <filename>/usr/</filename> entry found in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
         <para><varname>mount.usr=</varname> is honored by the initrd.
       <varlistentry>
         <term><varname>mount.usrfstype=</varname></term>
 
-        <listitem><para>Takes the <filename>/usr</filename> filesystem
+        <listitem><para>Takes the <filename>/usr/</filename> filesystem
         type that will be passed to the mount command. If
         <varname>mount.usr=</varname> or
         <varname>mount.usrflags=</varname> is set, then
         set in <varname>rootfstype=</varname>.</para>
 
         <para>Otherwise, this value will be read from the
-        <filename>/usr</filename> entry in
+        <filename>/usr/</filename> entry in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
         <para><varname>mount.usrfstype=</varname> is honored by the
       <varlistentry>
         <term><varname>mount.usrflags=</varname></term>
 
-        <listitem><para>Takes the <filename>/usr</filename> filesystem
+        <listitem><para>Takes the <filename>/usr/</filename> filesystem
         mount options to use. If <varname>mount.usr=</varname> or
         <varname>mount.usrfstype=</varname> is set, then
         <varname>mount.usrflags=</varname> will default to the value
         set in <varname>rootflags=</varname>.</para>
 
         <para>Otherwise, this value will be read from the
-        <filename>/usr</filename> entry in
+        <filename>/usr/</filename> entry in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
         <para><varname>mount.usrflags=</varname> is honored by the
         <citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         is run as part of the initial RAM disk ("initrd"). This service changes the mount table before transitioning to
         the host system, so that a volatile memory file system (<literal>tmpfs</literal>) is used as root directory,
-        with only <filename>/usr</filename> mounted into it from the configured root file system, in read-only
+        with only <filename>/usr/</filename> mounted into it from the configured root file system, in read-only
         mode. This way the system operates in fully stateless mode, with all configuration and state reset at boot and
-        lost at shutdown, as <filename>/etc</filename> and <filename>/var</filename> will be served from the (initially
+        lost at shutdown, as <filename>/etc/</filename> and <filename>/var/</filename> will be served from the (initially
         unpopulated) volatile memory file system.</para>
 
         <para>If set to <option>state</option> the generator will leave the root directory mount point unaltered,
-        however will mount a <literal>tmpfs</literal> file system to <filename>/var</filename>. In this mode the normal
-        system configuration (i.e. the contents of <literal>/etc</literal>) is in effect (and may be modified during
-        system runtime), however the system state (i.e. the contents of <literal>/var</literal>) is reset at boot and
+        however will mount a <literal>tmpfs</literal> file system to <filename>/var/</filename>. In this mode the normal
+        system configuration (i.e. the contents of <literal>/etc/</literal>) is in effect (and may be modified during
+        system runtime), however the system state (i.e. the contents of <literal>/var/</literal>) is reset at boot and
         lost at shutdown.</para>
 
         <para>If this setting is set to <literal>overlay</literal> the root file system is set up as
         <literal>tmpfs</literal>, so that no modifications are made to disk, but the file system may be modified
         nonetheless with all changes being lost at reboot.</para>
 
-        <para>Note that in none of these modes the root directory, <filename>/etc</filename>, <filename>/var</filename>
+        <para>Note that in none of these modes the root directory, <filename>/etc/</filename>, <filename>/var/</filename>
         or any other resources stored in the root file system are physically removed. It's thus safe to boot a system
         that is normally operated in non-volatile mode temporarily into volatile mode, without losing data.</para>
 
         <para>Note that with the exception of <literal>overlay</literal> mode, enabling this setting will only work
-        correctly on operating systems that can boot up with only <filename>/usr</filename> mounted, and are able to
-        automatically populate <filename>/etc</filename>, and also <filename>/var</filename> in case of
+        correctly on operating systems that can boot up with only <filename>/usr/</filename> mounted, and are able to
+        automatically populate <filename>/etc/</filename>, and also <filename>/var/</filename> in case of
         <literal>systemd.volatile=yes</literal>.</para></listitem>
       </varlistentry>
 
index f532a19a48a387178bcc225ee39a901973d8ec6a..60d66b201da6105cf9192e0b75f2e75be13145e8 100644 (file)
@@ -49,7 +49,7 @@
 
         <listitem><para>Takes a path to the resume device. Both
         persistent block device paths like
-        <filename>/dev/disk/by-foo/bar</filename> and
+        <filename index="false">/dev/disk/by-foo/bar</filename> and
         <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-style
         specifiers like <literal>FOO=bar</literal> are
         supported.</para></listitem>
index ab8bcab8cb852a5ecb5f5dfbd762b9666e3b99f8..d6a239bc96e1a5cce33fee9a505c63e56cfcdcd4 100644 (file)
@@ -86,9 +86,9 @@
     <para>In order to migrate a home directory from a host <literal>foobar</literal> to another host
     <literal>quux</literal> it is hence sufficient to copy
     <filename>/var/lib/systemd/home/local.public</filename> from the host <literal>foobar</literal> to
-    <literal>quux</literal>, maybe calling the file on the destination
-    <filename>/var/lib/systemd/home/foobar.public</filename>, reflecting the origin of the key. If the user
-    record should be modifiable on <literal>quux</literal> the pair
+    <literal>quux</literal>, maybe calling the file on the destination <filename
+    index="false">/var/lib/systemd/home/foobar.public</filename>, reflecting the origin of the key. If the
+    user record should be modifiable on <literal>quux</literal> the pair
     <filename>/var/lib/systemd/home/local.public</filename> and
     <filename>/var/lib/systemd/home/local.private</filename> need to be copied from <literal>foobar</literal>
     to <literal>quux</literal>, and placed under the identical paths there, as currently only a single
index 6b7a0bc4b998a60846de4291e17b943a218de368..1ed36dace9fd3b9572ba50e7f73facafb46aaf89 100644 (file)
@@ -179,8 +179,8 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
 
         <listitem><para>Request that journal data from <filename>/run/</filename> is flushed to
         <filename>/var/</filename> in order to make it persistent (if this is enabled). This must be used
-        after <filename>/var/</filename> is mounted, as otherwise log data from <filename>/run</filename> is
-        never flushed to <filename>/var</filename> regardless of the configuration. Use the
+        after <filename>/var/</filename> is mounted, as otherwise log data from <filename>/run/</filename> is
+        never flushed to <filename>/var/</filename> regardless of the configuration. Use the
         <command>journalctl --flush</command> command to request flushing of the journal files, and wait for
         the operation to complete. See
         <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
@@ -292,7 +292,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
         stopped uncleanly, or if the files are found to be corrupted,
         they are renamed using the <literal>.journal~</literal>
         suffix, and <command>systemd-journald</command> starts writing
-        to a new file. <filename>/run</filename> is used when
+        to a new file. <filename>/run/</filename> is used when
         <filename>/var/log/journal</filename> is not available, or
         when <option>Storage=volatile</option> is set in the
         <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
index 781a9845fb9e71be692b825e43cb88bfa397452a..40c9f436cf4a45017b94caf7da2e0f48005a7a47 100644 (file)
@@ -57,7 +57,7 @@
     transient machine ID file on a memory file system, and mount it
     over <filename>/etc/machine-id</filename>, during the early boot
     phase. This service is then invoked in a later boot phase, as soon
-    as <filename>/etc</filename> has been remounted writable and the
+    as <filename>/etc/</filename> has been remounted writable and the
     ID may thus be committed to disk to make it permanent.</para>
   </refsect1>
 
index 7caf35f8e8ebcfa066c6fa0e0a09057baa8cac9a..0454c11c8cf4e03f73ce42abe6f94b4e466056f6 100644 (file)
         <literal>tmpfs</literal>) to
         <filename>/etc/machine-id</filename> during the early phase of
         the boot process. This may happen because
-        <filename>/etc</filename> is initially read-only and was
+        <filename>/etc/</filename> is initially read-only and was
         missing a valid machine ID file at that point.</para>
 
         <para>This command will execute no operation if
         <filename>/etc/machine-id</filename> is not mounted from a
-        memory file system, or if <filename>/etc</filename> is
+        memory file system, or if <filename>/etc/</filename> is
         read-only. The command will write the current transient
         machine ID to disk and unmount the
         <filename>/etc/machine-id</filename> mount point in a
index a976c606bd8545649de9ea4878d4174a2aed1e1f..a6b1aa0f1389cda4d6872062dc4782dc3bc5979f 100644 (file)
     For more information please consult
     <citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     and
-    <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     and
-    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     </para>
 
     <para>A small companion daemon
index e960609c6cf812cc08b9ae571a9635a3ef3606c2..b849b81939d0815c244652347878774269b88a73 100644 (file)
@@ -30,8 +30,8 @@
     <title>Description</title>
 
     <para><filename>systemd-modules-load.service</filename> is an early boot service that loads kernel
-    modules. It reads static configuration from files in <filename>/usr</filename> and
-    <filename>/etc</filename>, but also runtime configuration from <filename>/run</filename> and the kernel
+    modules. It reads static configuration from files in <filename>/usr/</filename> and
+    <filename>/etc/</filename>, but also runtime configuration from <filename>/run/</filename> and the kernel
     command line (see below).</para>
 
     <para>See
index f1089eed3b0f3d6ed58fff63be41dca84979c290..3641c90248aa30c06629fd5456e0b4ddeb743eec 100644 (file)
         <term><option>--type=</option></term>
         <term><option>-t</option></term>
 
-        <listitem><para>Specifies the file system type to mount (e.g. <literal>vfat</literal>, <literal>ext4</literal>,
-        …). If omitted (or set to <literal>auto</literal>) the file system is determined automatically.</para></listitem>
+        <listitem><para>Specifies the file system type to mount (e.g. <literal>vfat</literal> or
+        <literal>ext4</literal>). If omitted or set to <literal>auto</literal>, the file system type is
+        determined automatically.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 6d583003baca6c1e531da3e91011f17ac0b446f7..f61bfd9980925c6bc00ae1db484239dcfeedf25d 100644 (file)
       <varlistentry>
         <term><option>--no-block</option></term>
 
-        <listitem><para>Do not synchronously wait for the requested operation to finish.
-        Use of this option is only recommended when <command>systemd-notify</command>
-        is spawned by the service manager, or when the invoking process is directly spawned
-        by the service manager and has enough privileges to allow <command>systemd-notify
-        </command> to send the notification on its behalf. Sending notifications with
+        <listitem><para>Do not synchronously wait for the requested operation to finish.  Use of this option
+        is only recommended when <command>systemd-notify</command> is spawned by the service manager, or when
+        the invoking process is directly spawned by the service manager and has enough privileges to allow
+        <command>systemd-notify</command> to send the notification on its behalf. Sending notifications with
         this option set is prone to race conditions in all other cases.</para></listitem>
       </varlistentry>
 
index 7c89bc44238b5990dcffb75253a6235aa876d10c..8152cf0f1351316009fe53bdeff8f4ed12968d48 100644 (file)
@@ -52,7 +52,7 @@
     <para><command>systemd-nspawn</command> may be invoked on any directory tree containing an operating system tree,
     using the <option>--directory=</option> command line option. By using the <option>--machine=</option> option an OS
     tree is automatically searched for in a couple of locations, most importantly in
-    <filename>/var/lib/machines</filename>, the suggested directory to place OS container images installed on the
+    <filename>/var/lib/machines/</filename>, the suggested directory to place OS container images installed on the
     system.</para>
 
     <para>In contrast to <citerefentry
@@ -60,7 +60,7 @@
     may be used to boot full Linux-based operating systems in a container.</para>
 
     <para><command>systemd-nspawn</command> limits access to various kernel interfaces in the container to read-only,
-    such as <filename>/sys</filename>, <filename>/proc/sys</filename> or <filename>/sys/fs/selinux</filename>. The
+    such as <filename>/sys/</filename>, <filename>/proc/sys/</filename> or <filename>/sys/fs/selinux/</filename>. The
     host's network interfaces and the system clock may not be changed from within the container. Device nodes may not
     be created. The host system cannot be rebooted and kernel modules may not be loaded from within the
     container.</para>
     template unit file, making it usually unnecessary to alter this template file directly.</para>
 
     <para>Note that <command>systemd-nspawn</command> will mount file systems private to the container to
-    <filename>/dev</filename>, <filename>/run</filename> and similar. These will not be visible outside of the
+    <filename>/dev/</filename>, <filename>/run/</filename> and similar. These will not be visible outside of the
     container, and their contents will be lost when the container exits.</para>
 
     <para>Note that running two <command>systemd-nspawn</command> containers from the same directory tree will not make
         terminated. When the mode parameter is specified as <option>no</option> (the default), the whole OS tree is
         made available writable (unless <option>--read-only</option> is specified, see above).</para>
 
-        <para>Note that if one of the volatile modes is chosen, its effect is limited to the root file system (or
-        <filename>/var/</filename> in case of <option>state</option>), and any other mounts placed in the hierarchy are
-        unaffected — regardless if they are established automatically (e.g. the EFI system partition that might be
-        mounted to <filename>/efi/</filename> or <filename>/boot/</filename>) or explicitly (e.g. through an additional
-        command line option such as <option>--bind=</option>, see below). This means, even if
-        <option>--volatile=overlay</option> is used changes to <filename>/efi/</filename> or
-        <filename>/boot/</filename> are prohibited in case such a partition exists in the container image operated on,
-        and even if <option>--volatile=state</option> is used the hypothetical file <filename>/etc/foobar</filename> is
-        potentially writable if <option>--bind=/etc/foobar</option> if used to mount it from outside the read-only
-        container <filename>/etc</filename> directory.</para>
+        <para>Note that if one of the volatile modes is chosen, its effect is limited to the root file system
+        (or <filename>/var/</filename> in case of <option>state</option>), and any other mounts placed in the
+        hierarchy are unaffected — regardless if they are established automatically (e.g. the EFI system
+        partition that might be mounted to <filename>/efi/</filename> or <filename>/boot/</filename>) or
+        explicitly (e.g. through an additional command line option such as <option>--bind=</option>, see
+        below). This means, even if <option>--volatile=overlay</option> is used changes to
+        <filename>/efi/</filename> or <filename>/boot/</filename> are prohibited in case such a partition
+        exists in the container image operated on, and even if <option>--volatile=state</option> is used the
+        hypothetical file <filename index="false">/etc/foobar</filename> is potentially writable if
+        <option>--bind=/etc/foobar</option> if used to mount it from outside the read-only container
+        <filename>/etc/</filename> directory.</para>
 
         <para>The <option>--ephemeral</option> option is closely related to this setting, and provides similar
         behaviour by making a temporary, ephemeral copy of the whole OS image and executing that. For further details,
         <literal>user.verity.usrhash</literal> extended file attribute or via a <filename>.usrhash</filename>
         file adjacent to the disk image, following the same format and logic as for the root hash for the
         root file system described here. Note that there's currently no switch to configure the root hash for
-        the <filename>/usr/</filename> from the command line.</para></listitem>
+        the <filename>/usr/</filename> from the command line.</para>
+
+        <para>Also see the <varname>RootHash=</varname> option in
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--root-hash-sig=</option></term>
 
-        <listitem><para>Takes a PKCS7 formatted binary signature of the <option>--root-hash=</option> option as a path
-        to a DER encoded signature file or as an ASCII base64 string encoding of the DER encoded signature, prefixed
-        by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root hash hex
-        string is valid and done by a public key present in the kernel keyring. If this option is not specified, but a
-        file with the <filename>.roothash.p7s</filename> suffix is found next to the image file, bearing otherwise the
-        same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file must
-        not have it in its name), the signature is read from it and automatically used.</para>
-
-        <para>The root hash for the <filename>/usr/</filename> file system included in a disk image may be
-        configured via a <filename>.usrhash.p7s</filename> file adjacent to the disk image. There's currently
-        no switch to configure the signature of the root hash of the <filename>/usr/</filename> file system
-        from the command line.</para></listitem>
+        <listitem><para>Takes a PKCS7 signature of the <option>--root-hash=</option> option.
+        The semantics are the same as for the <varname>RootHashSignature=</varname> option, see
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
         and mount options. The source path may optionally be prefixed with a <literal>+</literal> character. If so, the
         source path is taken relative to the image's root directory. This permits setting up bind mounts within the
         container image. The source path may be specified as empty string, in which case a temporary directory below
-        the host's <filename>/var/tmp</filename> directory is used. It is automatically removed when the container is
+        the host's <filename>/var/tmp/</filename> directory is used. It is automatically removed when the container is
         shut down. Mount options are comma-separated and currently, only <option>rbind</option> and
         <option>norbind</option> are allowed, controlling whether to create a recursive or a regular bind
         mount. Defaults to "rbind". Backslash escapes are interpreted, so <literal>\:</literal> may be used to embed
         point for the overlay file system in the container. At least
         two paths have to be specified.</para>
 
-        <para>The source paths may optionally be prefixed with <literal>+</literal> character. If so they are taken
-        relative to the image's root directory. The uppermost source path may also be specified as empty string, in
-        which case a temporary directory below the host's <filename>/var/tmp</filename> is used. The directory is
-        removed automatically when the container is shut down. This behaviour is useful in order to make read-only
-        container directories writable while the container is running. For example, use the
-        <literal>--overlay=+/var::/var</literal> option in order to automatically overlay a writable temporary
-        directory on a read-only <filename>/var</filename> directory.</para>
+        <para>The source paths may optionally be prefixed with <literal>+</literal> character. If so they are
+        taken relative to the image's root directory. The uppermost source path may also be specified as an
+        empty string, in which case a temporary directory below the host's <filename>/var/tmp/</filename> is
+        used. The directory is removed automatically when the container is shut down. This behaviour is
+        useful in order to make read-only container directories writable while the container is running. For
+        example, use <literal>--overlay=+/var::/var</literal> in order to automatically overlay a writable
+        temporary directory on a read-only <filename>/var/</filename> directory.</para>
 
         <para>For details about overlay file systems, see <ulink
         url="https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt">overlayfs.txt</ulink>. Note
diff --git a/man/systemd-oomd.service.xml b/man/systemd-oomd.service.xml
new file mode 100644 (file)
index 0000000..9d72373
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd-oomd.service" conditional='ENABLE_OOMD'>
+
+  <refentryinfo>
+    <title>systemd-oomd.service</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>systemd-oomd.service</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>systemd-oomd.service</refname>
+    <refname>systemd-oomd</refname>
+    <refpurpose>A userspace out-of-memory (OOM) killer</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>systemd-oomd.service</filename></para>
+    <para><filename>/usr/lib/systemd/systemd-oomd</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>systemd-oomd</command> is a system service that uses cgroups-v2 and pressure stall information (PSI)
+    to monitor and take action on processes before an OOM occurs in kernel space.</para>
+
+    <para>You can enable monitoring and actions on units by setting <varname>ManagedOOMSwap=</varname> and/or
+    <varname>ManagedOOMMemoryPressure=</varname> to the appropriate value. <command>systemd-oomd</command> will
+    periodically poll enabled units' cgroup data to detect when corrective action needs to occur. When an action needs
+    to happen, it will only be performed on the descendant cgroups of the enabled units. More precisely, only cgroups with
+    <filename>memory.oom.group</filename> set to <constant>1</constant> and leaf cgroup nodes are eligible candidates.
+    Action will be taken recursively on all of the processes under the chosen candidate.</para>
+
+    <para>See
+    <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for more information about the configuration of this service.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Setup Information</title>
+
+    <para>The system must be running systemd with a full unified cgroup hierarchy for the expected cgroups-v2 features.
+    Furthermore, resource accounting must be turned on for all units monitored by <command>systemd-oomd</command>.
+    The easiest way to turn on resource accounting is by ensuring the values for <varname>DefaultCPUAccounting</varname>,
+    <varname>DefaultIOAccounting</varname>, <varname>DefaultMemoryAccounting</varname>, and
+    <varname>DefaultTasksAccounting</varname> are set to <constant>true</constant> in
+    <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+    <para>You will need a kernel compiled with PSI support. This is available in Linux 4.20 and above.</para>
+
+    <para>The system must also have swap enabled for <command>systemd-oomd</command> to function correctly. With swap
+    enabled, the system spends enough time swapping pages to let <command>systemd-oomd</command> react.
+    Without swap, the system enters a livelocked state much more quickly and may prevent <command>systemd-oomd</command>
+    from responding in a reasonable amount of time. See
+    <ulink url="https://chrisdown.name/2018/01/02/in-defence-of-swap.html">"In defence of swap: common misconceptions"</ulink>
+    for more details on swap.</para>
+
+    <para>Be aware that if you intend to enable monitoring and actions on <filename>user.slice</filename>,
+    <filename>user-$UID.slice</filename>, or their ancestor cgroups, it is highly recommended that your programs be
+    managed by the systemd user manager to prevent running too many processes under the same session scope (and thus
+    avoid a situation where memory intensive tasks trigger <command>systemd-oomd</command> to kill everything under the
+    cgroup). If you're using a desktop environment like GNOME, it already spawns many session components with the
+    systemd user manager.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Usage Recommendations</title>
+
+    <para><varname>ManagedOOMSwap=</varname> works with the system-wide swap values, so setting it on the root slice
+    <filename>-.slice</filename>, and allowing all descendant cgroups to be eligible candidates may make the most
+    sense.</para>
+
+    <para><varname>ManagedOOMMemoryPressure=</varname> tends to work better on the cgroups below the root slice
+    <filename>-.slice</filename>. For units which tend to have processes that are less latency sensitive (e.g.
+    <filename>system.slice</filename>), a higher limit like the default of 60% may be acceptable, as those processes
+    can usually ride out slowdowns caused by lack of memory without serious consequences. However, something like
+    <filename>user@$UID.service</filename> may prefer a much lower value like 40%.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>oomctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
index a744df751b8e346879e798189f3dfffbb2d78098..4f89156264a2e521eb658d7c728b10d01038286a 100644 (file)
     project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>, or
     gathered from the partition table (when
     <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    is active) to the root file system, the <filename>/usr</filename> file system, and the kernel API file
+    is active) to the root file system, the <filename>/usr/</filename> file system, and the kernel API file
     systems. This is required so that the mount options of these file systems — which are pre-mounted by the
     kernel, the initial RAM disk, container environments or system manager code — are updated to those
     configured in <filename>/etc/fstab</filename> and the other sources. This service ignores normal file
-    systems and only changes the root file system (i.e.  <filename>/</filename>), <filename>/usr</filename>,
-    and the virtual kernel API file systems such as <filename>/proc</filename>, <filename>/sys</filename> or
-    <filename>/dev</filename>. This service executes no operation if no configuration is found
+    systems and only changes the root file system (i.e.  <filename>/</filename>), <filename>/usr/</filename>,
+    and the virtual kernel API file systems such as <filename>/proc/</filename>, <filename>/sys/</filename> or
+    <filename>/dev/</filename>. This service executes no operation if no configuration is found
     (<filename>/etc/fstab</filename> does not exist or lists no entries for the mentioned file systems, or
     the partition table does not contain relevant entries).</para>
 
index 914607e3f8d621827dec247c19eac3144fb3a757..8f3494e36b0b16cbd672c655544f1d1129daae9d 100644 (file)
   <refsect1>
     <title>Synthetic Records</title>
 
-    <para><command>systemd-resolved</command> synthesizes DNS resource records (RRs) for the following
+    <para><command>systemd-resolved</command> synthetizes DNS resource records (RRs) for the following
     cases:</para>
 
     <itemizedlist>
       <listitem><para>The local, configured hostname is resolved to all locally configured IP addresses
       ordered by their scope, or — if none are configured — the IPv4 address 127.0.0.2 (which is on the local
-      loopback) and the IPv6 address ::1 (which is the local host).</para></listitem>
+      loopback interface) and the IPv6 address ::1 (which is the local host).</para></listitem>
 
       <listitem><para>The hostnames <literal>localhost</literal> and <literal>localhost.localdomain</literal>
-      (as well as any hostname ending in <literal>.localhost</literal> or
-      <literal>.localhost.localdomain</literal>) are resolved to the IP addresses 127.0.0.1 and ::1.
+      as well as any hostname ending in <literal>.localhost</literal> or
+      <literal>.localhost.localdomain</literal> are resolved to the IP addresses 127.0.0.1 and ::1.
       </para></listitem>
 
       <listitem><para>The hostname <literal>_gateway</literal> is resolved to all current default routing
     according to the following rules:</para>
 
     <itemizedlist>
-      <listitem><para>Names for which synthetic records are generated (as listed in the previous section) are
-      never routed to the network and a reply is sent immediately. In particular this means that lookups for
-      <literal>localhost</literal> are never routed to the network.</para></listitem>
-
-      <listitem><para>Single-label names are routed to all local interfaces capable of IP multicasting, where
-      LLMNR is not disabled, using the LLMNR protocol. Lookups for IPv4 addresses are only sent via LLMNR on
-      IPv4, and lookups for IPv6 addresses are only sent via LLMNR on IPv6. Lookups for the locally
-      configured hostname and the <literal>_gateway</literal> hostname are never routed to LLMNR.
-      </para></listitem>
-
-      <listitem><para>Multi-label names with the domain suffix <literal>.local</literal> are routed to all
-      local interfaces capable of IP multicasting, where MulticastDNS is not disabled, using the MulticastDNS
-      protocol. As with LLMNR, IPv4 address lookups are sent via IPv4 and IPv6 address lookups are sent via
-      IPv6.</para></listitem>
-
-      <listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or
-      MulticastDNS) for non-synthesized single-label names is allowed for non-top-level domains. This means
-      that such records can be resolved when search domains are defined. For any interface which defines
-      search domains, such look-ups are routed to that interface, suffixed with each of the search domains
-      defined on that interface in turn. When global search domains are defined, such look-ups are routed to
-      all interfaces, suffixed by each of the global search domains in turn. Additionally, lookup of
-      single-label names via unicast DNS may be enabled with the
-      <varname>ResolveUnicastSingleLabel=yes</varname> setting. The details of which servers are queried and
-      how the final reply is chosen are described below. Note that this means that address queries for
-      single-label names are never sent out to remote DNS servers by default, and if no search domains are
-      defined, resolution will fail.</para></listitem>
-
-      <listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server
-      configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for
-      domains with the <literal>.local</literal> suffix are not routed to DNS servers, unless the domain is
-      specified explicitly as routing or search domain for the DNS server and interface. This means that on
-      networks where the <literal>.local</literal> domain is defined in a site-specific DNS server, explicit
-      search or routing domains need to be configured to make lookups within this DNS domain work. Note that
-      these days, it's generally recommended to avoid defining <literal>.local</literal> in a DNS server, as
-      <ulink url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
+      <listitem><para>Names for which synthetic records are generated (the local hostname,
+      <literal>localhost</literal> and <literal>localdomain</literal>, local gateway, as listed in the
+      previous section) and addresses configured in <filename>/etc/hosts</filename> are never routed to the
+      network and a reply is sent immediately.</para></listitem>
+
+      <listitem><para>Single-label names are resolved using LLMNR on all local interfaces where LLMNR is
+      enabled. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6 addresses are
+      only sent via LLMNR on IPv6. Note that lookups for single-label synthetized names are not routed to
+      LLMNR, MulticastDNS or unicast DNS.</para></listitem>
+
+      <listitem><para>Queries for the address records (A and AAAA) of single-label non-synthetized names are
+      resolved via unicast DNS using search domains. For any interface which defines search domains, such
+      look-ups are routed to that interface, suffixed with each of the search domains defined on that
+      interface in turn. When global search domains are defined, such look-ups are routed to all interfaces,
+      suffixed by each of the global search domains in turn. Additionally, lookup of single-label names via
+      unicast DNS may be enabled with the <varname>ResolveUnicastSingleLabel=yes</varname> setting. The
+      details of which servers are queried and how the final reply is chosen are described below. Note that
+      this means that address queries for single-label names are never sent out to remote DNS servers by
+      default, and resoulution is only possible if search domains are defined.</para></listitem>
+
+      <listitem><para>Multi-label names with the domain suffix <literal>.local</literal> are resolved using
+      MulticastDNS on all local interfaces where MulticastDNS is enabled. As with LLMNR, IPv4 address lookups
+      are sent via IPv4 and IPv6 address lookups are sent via IPv6.</para></listitem>
+
+      <listitem><para>Queries for multi-label names are routed via unicast DNS on local interfaces that have
+      a DNS server configured, plus the globally configured DNS servers if there are any. Which interfaces
+      are used is determined by the routing logic based on search and route-only domains, described below.
+      Note that by default, lookups for domains with the <literal>.local</literal> suffix are not routed to
+      DNS servers, unless the domain is specified explicitly as routing or search domain for the DNS server
+      and interface. This means that on networks where the <literal>.local</literal> domain is defined in a
+      site-specific DNS server, explicit search or routing domains need to be configured to make lookups work
+      within this DNS domain. Note that these days, it's generally recommended to avoid defining
+      <literal>.local</literal> in a DNS server, as <ulink
+      url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
       MulticastDNS use.</para></listitem>
 
-      <listitem><para>Address lookups are routed similarly to multi-label names, with the exception that
-      addresses from the link-local address range are never routed to unicast DNS and are only resolved using
-      LLMNR and MulticastDNS (when enabled).</para></listitem>
+      <listitem><para>Address lookups (reverse lookups) are routed similarly to multi-label names, with the
+      exception that addresses from the link-local address range are never routed to unicast DNS and are only
+      resolved using LLMNR and MulticastDNS (when enabled).</para></listitem>
     </itemizedlist>
 
     <para>If lookups are routed to multiple interfaces, the first successful response is returned (thus
     effectively merging the lookup zones on all matching interfaces). If the lookup failed on all interfaces,
     the last failing response is returned.</para>
 
-    <para>Routing of lookups may be influenced by configuring per-interface domain names and other
-    settings. See
+    <para>Routing of lookups is determined by the per-interface routing domains (search and route-only) and
+    global search domains. See
     <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> and
-    <citerefentry><refentrytitle>resolvectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
-    details. The following query routing logic applies for unicast DNS traffic:</para>
+    <citerefentry><refentrytitle>resolvectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for a
+    description how those settings are set dynamically and the discussion of <varname>Domains=</varname> in
+    <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for a
+    description of globally configured DNS settings.</para>
+
+    <para>The following query routing logic applies for unicast DNS traffic:</para>
 
     <itemizedlist>
       <listitem><para>If a name to look up matches (that is: is equal to or has as suffix) any of the
-      configured search or route-only domains of any link (see
-      <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
-      or the globally configured DNS settings (see the discussion of <varname>Domains=</varname> in
-      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
-      "best matching" search/route-only domain is determined: the matching one with the most labels. The
-      query is then sent to all DNS servers of any links or the globally configured DNS servers associated
-      with this "best matching" search/route-only domain. (Note that more than one link might have this same
-      "best matching" search/route-only domain configured, in which case the query is sent to all of them in
-      parallel).</para>
+      configured routing domains (search or route-only) of any link, or the globally configured DNS settings,
+      "best matching" routing domain is determined: the matching one with the most labels. The query is then
+      sent to all DNS servers of any links or the globally configured DNS servers associated with this "best
+      matching" routing domain. (Note that more than one link might have this same "best matching" routing
+      domain configured, in which case the query is sent to all of them in parallel).</para>
 
       <para>In case of single-label names, when search domains are defined, the same logic applies, except
-      that the name is first suffixed by the search domain.</para></listitem>
+      that the name is first suffixed by each of the search domains in turn. Note that this search logic
+      doesn't apply to any names with at least one dot. Also see the discussion about compatiblity with
+      the traditional glibc resolver below.</para></listitem>
 
-      <listitem><para>If a query does not match any configured search/route-only domain (neither per-link nor
-      global), it is sent to all DNS servers that are configured on links with the "DNS default route" option
-      set, as well as the globally configured DNS server.</para></listitem>
+      <listitem><para>If a query does not match any configured routing domain (either per-link or global), it
+      is sent to all DNS servers that are configured on links with the <varname>DefaultRoute=</varname>
+      option set, as well as the globally configured DNS server.</para></listitem>
 
-      <listitem><para>If there is no link configured as "DNS default route" and no global DNS server
-      configured, the compiled-in fallback DNS server is used.</para></listitem>
+      <listitem><para>If there is no link configured as <varname>DefaultRoute=</varname> and no global DNS
+      server configured, one of the compiled-in fallback DNS servers is used.</para></listitem>
 
-      <listitem><para>Otherwise the query is failed as no suitable DNS servers could be determined.
+      <listitem><para>Otherwise the unicast DNS query fails, as no suitable DNS servers can be determined.
       </para></listitem>
     </itemizedlist>
 
-    <para>The "DNS default route" option is a boolean setting configurable with <command>resolvectl</command>
-    or in <filename>.network</filename> files. If not set, it is implicitly determined based on the
-    configured DNS domains for a link: if there's any route-only domain (not matching <literal>~.</literal>)
-    it defaults to false, otherwise to true.</para>
+    <para>The <varname>DefaultRoute=</varname> option is a boolean setting configurable with
+    <command>resolvectl</command> or in <filename>.network</filename> files. If not set, it is implicitly
+    determined based on the configured DNS domains for a link: if there's a route-only domain other than
+    <literal>~.</literal>, it defaults to false, otherwise to true.</para>
 
     <para>Effectively this means: in order to support single-label non-synthetized names, define appropriate
-    search domains. In order to preferably route all DNS queries not explicitly matched by search/route-only
-    domain configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This
-    will ensure that other links will not be considered for these queries (unless they too carry such a
-    route-only domain). In order to route all such DNS queries to a specific link only if no other link
-    is preferable, set the "DNS default route" option for the link to true and do not configure a
+    search domains. In order to preferably route all DNS queries not explicitly matched by routing domain
+    configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This will
+    ensure that other links will not be considered for these queries (unless they too carry such a routing
+    domain). In order to route all such DNS queries to a specific link only if no other link is preferred,
+    set the <varname>DefaultRoute=</varname> option for the link to true and do not configure a
     <literal>~.</literal> route-only domain on it. Finally, in order to ensure that a specific link never
-    receives any DNS traffic not matching any of its configured search/route-only domains, set the "DNS
-    default route" option for it to false.</para>
+    receives any DNS traffic not matching any of its configured routing domains, set the
+    <varname>DefaultRoute=</varname> option for it to false.</para>
 
-    <para>See the <ulink url="https://www.freedesktop.org/wiki/Software/systemd/resolved">resolved D-Bus API
-    Documentation</ulink> for information about the APIs <filename>systemd-resolved</filename> provides.
-    </para>
+    <para>See
+    <citerefentry><refentrytitle>org.freedesktop.resolve1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for information about the D-Bus APIs <filename>systemd-resolved</filename> provides.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Compatibility with the traditional glibc stub resolver</title>
+
+    <para>This section provides a short summary of differences in the stub resolver implemented by
+    <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry> together
+    with <command>systemd-resolved</command> and the tranditional stub resolver implemented in
+    <citerefentry><refentrytitle>nss-dns</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+    <itemizedlist>
+      <listitem><para>Some names are always resolved internally (see Synthetic Records above). Traditionally
+      they would be resolved by <filename>nss-files</filename>, and only if provided in
+      <filename>/etc/hosts</filename>.</para></listitem>
+
+      <listitem><para>Single-label names are not resolved for A and AAAA records using unicast DNS (unless
+      overriden with <varname>ResolveUnicastSingleLabel=</varname>, see
+      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+      This is similar to the <option>no-tld-query</option> option being set in
+      <citerefentry><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+      </para></listitem>
+
+      <listitem><para>Search domains are not used for <emphasis>suffixing</emphasis> of multi-label names.
+      (Search domains are nevertheless used for lookup <emphasis>routing</emphasis>, for names that were
+      originally specified as single-label or multi-label.) Any name with at least one dot is always
+      interpreted as a FQDN. <filename>nss-dns</filename> would resolve names both as relative (using search
+      domains) and absolute FQDN names. Some names would be resolved as relative first, and after that query
+      has failed, as absolute, while other names would be resolved in opposite order. The
+      <varname>ndots</varname> option in <filename>/etc/resolv.conf</filename> was used to control how many
+      dots the name needs to have to be resolved as relative first. This stub resolver does not implement
+      this at all: multi-label names are only resolved as FQDNs. (There are currently more than 1500
+      top-level domain names defined, and new ones are added regularly, often using "attractive" names that
+      are also likely to be used locally. Not looking up multi-label names in this fashion avoids fragility
+      in both directions: a valid global name could be obscured by a local name, and resolution of a relative
+      local name could suddenly break when a new top-level domain is created, or when a new subdomain of a
+      top-level domain in registered. Resolving any given name as either relative or absolute avoids this
+      ambiguity.)</para></listitem>
+
+      <listitem><para>This resolver has a notion of the special <literal>.local</literal> domain used for
+      MulticastDNS, and will not route queries with that suffix to unicast DNS servers unless explicitly
+      configured, see above. Also, reverse lookups for link-local addresses are not sent to unicast DNS
+      servers.</para></listitem>
+
+      <listitem><para>This resolver reads and caches <filename>/etc/hosts</filename> internally. (In other
+      words, <filename>nss-resolve</filename> replaces <filename>nss-files</filename> in addition to
+      <filename>nss-dns</filename>). Entries in <filename>/etc/hosts</filename> have highest priority.</para>
+      </listitem>
+
+      <listitem><para>This resolver also implements LLMNR and MulticastDNS in addition to the classic unicast
+      DNS protocol, and will resolve single-label names using LLMNR (when enabled) and names ending in
+      <literal>.local</literal> using MulticastDNS (when enabled).</para></listitem>
+
+      <listitem><para>Environment variables <varname>$LOCALDOMAIN</varname> and
+      <varname>$RES_OPTIONS</varname> described in
+      <citerefentry><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> are not
+      supported currently.</para></listitem>
+    </itemizedlist>
   </refsect1>
 
   <refsect1>
         synchronous way.</para></listitem>
       </varlistentry>
     </variablelist>
-
   </refsect1>
 
   <refsect1>
index 7b04f4b70b909e6f6f8fcc6d52033751ee99f02a..fa1cbef586b1f0eccb63dba95795c04bd87cca18 100644 (file)
@@ -51,7 +51,7 @@
     <para>See
     <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for information about the configuration of sysctl settings. After sysctl configuration is
-    changed on disk, it must be written to the files in <filename>/proc/sys</filename> before it
+    changed on disk, it must be written to the files in <filename>/proc/sys/</filename> before it
     takes effect. It is possible to update specific settings, or simply to reload all configuration,
     see Examples below.</para>
   </refsect1>
index ec7d12b9ca00537de102fb4ba41bdfb492ca3c4d..b6011c344a8a5205c1b43eb32e177e4328212bb9 100644 (file)
@@ -78,8 +78,8 @@
     and administrator-controlled files under <filename>/usr/share/user-tmpfiles.d/</filename>. Users may use
     this to create and clean up files under their control, but the system instance performs global cleanup
     and is not influenced by user configuration. Note that this means a time-based cleanup configured in the
-    system instance, such as the one typically configured for <filename>/tmp</filename>, will thus also
-    affect files created by the user instance if they are placed in <filename>/tmp</filename>, even if the
+    system instance, such as the one typically configured for <filename>/tmp/</filename>, will thus also
+    affect files created by the user instance if they are placed in <filename>/tmp/</filename>, even if the
     user instance's time-based cleanup is turned off.</para>
   </refsect1>
 
index 8d9e9e0c1b76f5c5ac91c56f9625520067b76d50..36089dff83c11332e626d9bce07cdc5a4ddf3836 100644 (file)
@@ -39,8 +39,8 @@
     runtime.</para>
 
     <para><command>systemd-tty-ask-password-agent</command> implements
-    the <ulink url="https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">Password
-    Agents Specification</ulink>, and is one of many possible response agents which
+    the <ulink url="https://systemd.io/PASSWORD_AGENTS/">Password Agents
+    Specification</ulink>, and is one of many possible response agents which
     answer to queries formulated with
     <citerefentry><refentrytitle>systemd-ask-password</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
     </para>
index 91196dff301fb92ce9cab3b2a82ac8a627b82495..f26da5102abdbaf7f9df8eccc2e9d7583bd1aa6c 100644 (file)
@@ -18,7 +18,7 @@
   <refnamediv>
     <refname>systemd-update-done.service</refname>
     <refname>systemd-update-done</refname>
-    <refpurpose>Mark <filename>/etc</filename> and <filename>/var</filename> fully updated</refpurpose>
+    <refpurpose>Mark <filename>/etc/</filename> and <filename>/var/</filename> fully updated</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
 
     <para><filename>systemd-update-done.service</filename> is a
     service that is invoked as part of the first boot after the vendor
-    operating system resources in <filename>/usr</filename> have been
+    operating system resources in <filename>/usr/</filename> have been
     updated. This is useful to implement offline updates of
-    <filename>/usr</filename> which might require updates to
-    <filename>/etc</filename> or <filename>/var</filename> on the
+    <filename>/usr/</filename> which might require updates to
+    <filename>/etc/</filename> or <filename>/var/</filename> on the
     following boot.</para>
 
     <para><filename>systemd-update-done.service</filename> updates the
     file modification time (mtime) of the stamp files
     <filename>/etc/.updated</filename> and
     <filename>/var/.updated</filename> to the modification time of the
-    <filename>/usr</filename> directory, unless the stamp files are
+    <filename>/usr/</filename> directory, unless the stamp files are
     already newer.</para>
 
     <para>Services that shall run after offline upgrades of
-    <filename>/usr</filename> should order themselves before
+    <filename>/usr/</filename> should order themselves before
     <filename>systemd-update-done.service</filename>, and use the
     <varname>ConditionNeedsUpdate=</varname> (see
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
-    condition to make sure to run when <filename>/etc</filename> or
-    <filename>/var</filename> are older than <filename>/usr</filename>
+    condition to make sure to run when <filename>/etc/</filename> or
+    <filename>/var/</filename> are older than <filename>/usr/</filename>
     according to the modification times of the files described above.
-    This requires that updates to <filename>/usr</filename> are always
+    This requires that updates to <filename>/usr/</filename> are always
     followed by an update of the modification time of
-    <filename>/usr</filename>, for example by invoking
+    <filename>/usr/</filename>, for example by invoking
     <citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     on it.</para>
 
index 440e9eac7a1b72b63c6815a9871156f4ead14b2b..0b1f39e34d0e13841681436cd2fcb565af195372 100644 (file)
@@ -31,8 +31,8 @@
 
     <para><filename>systemd-volatile-root.service</filename> is a service that replaces the root directory with a
     volatile memory file system (<literal>tmpfs</literal>), mounting the original (non-volatile)
-    <filename>/usr</filename> inside it read-only. This way, vendor data from <filename>/usr</filename> is available as
-    usual, but all configuration data in <filename>/etc</filename>, all state data in <filename>/var</filename> and all
+    <filename>/usr/</filename> inside it read-only. This way, vendor data from <filename>/usr/</filename> is available as
+    usual, but all configuration data in <filename>/etc/</filename>, all state data in <filename>/var/</filename> and all
     other resources stored directly under the root directory are reset on boot and lost at shutdown, enabling fully
     stateless systems.</para>
 
index 085fd62bceef8d2428d48d7b818df4ec375e2d6e..49b59ebf13013ae06f3c10b837a0b5e671018877 100644 (file)
@@ -49,8 +49,8 @@
     <citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     for details.</para>
 
-    <para>Device units are named after the <filename>/sys</filename>
-    and <filename>/dev</filename> paths they control. Example: the
+    <para>Device units are named after the <filename>/sys/</filename>
+    and <filename>/dev/</filename> paths they control. Example: the
     device <filename index="false">/dev/sda5</filename> is exposed in
     systemd as <filename>dev-sda5.device</filename>. For details about
     the escaping logic used to convert a file system path to a unit
index d7e6caddf1e9bcea4794653cc1e900d0b693fdb1..c4f7ef6e6bcf757a4ebd18a5c1ad2f5cf618364b 100644 (file)
@@ -42,9 +42,9 @@
     <filename>/run/systemd/dnssd</filename> and the local administration network directory
     <filename>/etc/systemd/dnssd</filename>. All configuration files are collectively sorted and processed in
     lexical order, regardless of the directories in which they live. However, files with identical filenames
-    replace each other. Files in <filename>/etc</filename> have the highest priority, files in
-    <filename>/run</filename> take precedence over files with the same name in
-    <filename>/usr/lib</filename>. This can be used to override a system-supplied configuration file with a
+    replace each other. Files in <filename>/etc/</filename> have the highest priority, files in
+    <filename>/run/</filename> take precedence over files with the same name in
+    <filename>/usr/lib/</filename>. This can be used to override a system-supplied configuration file with a
     local file if needed.</para>
 
     <para>Along with the network service file <filename>foo.dnssd</filename>, a "drop-in" directory
@@ -55,8 +55,8 @@
 
     <para>In addition to <filename>/etc/systemd/dnssd</filename>, drop-in <literal>.d</literal> directories
     can be placed in <filename>/usr/lib/systemd/dnssd</filename> or <filename>/run/systemd/dnssd</filename>
-    directories. Drop-in files in <filename>/etc</filename> take precedence over those in
-    <filename>/run</filename> which in turn take precedence over those in <filename>/usr/lib</filename> or
+    directories. Drop-in files in <filename>/etc/</filename> take precedence over those in
+    <filename>/run/</filename> which in turn take precedence over those in <filename>/usr/lib/</filename> or
     <filename>/usr/local/lib</filename>. Drop-in files under any of these directories take precedence over
     the main network service file wherever located.</para>
   </refsect1>
index a806f7bcf3fd725aa64b05fdd3bd49f0f884bca5..4ffe89065d1fdcf5993dedf250e800650e9b9847 100644 (file)
@@ -65,7 +65,7 @@
     to <filename>/dev/null</filename> or an empty file can be used to mask a generator, thereby
     preventing it from running. Please note that the order of the two directories with the highest
     priority is reversed with respect to the unit load path, and generators in
-    <filename>/run</filename> overwrite those in <filename>/etc</filename>.</para>
+    <filename>/run/</filename> overwrite those in <filename>/etc/</filename>.</para>
 
     <para>After installing new generators or updating the configuration, <command>systemctl
     daemon-reload</command> may be executed. This will re-run all generators, updating environment
index ed657831f6f4cfd924a618ed7b1b117d645d0e00..9da919c3795b61edff4fd3e9f2a204cf69170217 100644 (file)
       paths.  This is equivalent to having them listed explicitly in
       <varname>RequiresMountsFor=</varname>.</para></listitem>
 
-      <listitem><para>Similar, units with <varname>PrivateTmp=</varname> enabled automatically get mount unit
-      dependencies for all mounts required to access <filename>/tmp</filename> and <filename>/var/tmp</filename>. They
-      will also gain an automatic <varname>After=</varname> dependency on
-      <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
+      <listitem><para>Similarly, units with <varname>PrivateTmp=</varname> enabled automatically get mount
+      unit dependencies for all mounts required to access <filename>/tmp/</filename> and
+      <filename>/var/tmp/</filename>. They will also gain an automatic <varname>After=</varname> dependency
+      on
+      <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+      </para></listitem>
 
       <listitem><para>Units whose standard output or error output is connected to <option>journal</option> or
       <option>kmsg</option> (or their combinations with console output, see below) automatically acquire
         case the image has multiple partitions, otherwise partition name <literal>root</literal> is implied.
         Options for multiple partitions can be specified in a single line with space separators. Assigning an empty
         string removes previous assignments. Duplicated options are ignored. For a list of valid mount options, please
-        refer to <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+        refer to
+        <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+        </para>
 
         <para>Valid partition names follow the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable
         Partitions Specification</ulink>.</para>
       <varlistentry>
         <term><varname>RootHashSignature=</varname></term>
 
-        <listitem><para>Takes a PKCS7 formatted binary signature of the <varname>RootHash=</varname> option as a path
-        to a DER encoded signature file or as an ASCII base64 string encoding of the DER encoded signature, prefixed
-        by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root hash
-        signature is valid and created by a public key present in the kernel keyring. If this option is not specified,
-        but a file with the <filename>.roothash.p7s</filename> suffix is found next to the image file, bearing otherwise
-        the same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file
-        must not have it in its name), the signature is read from it and automatically used.</para>
+        <listitem><para>Takes a PKCS7 signature of the <varname>RootHash=</varname> option as a path to a
+        DER-encoded signature file, or as an ASCII base64 string encoding of a DER-encoded signature prefixed
+        by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root
+        hash is valid and signed by a public key present in the kernel keyring. If this option is not
+        specified, but a file with the <filename>.roothash.p7s</filename> suffix is found next to the image
+        file, bearing otherwise the same name (except if the image has the <filename>.raw</filename> suffix,
+        in which case the signature file must not have it in its name), the signature is read from it and
+        automatically used.</para>
 
         <para>If the disk image contains a separate <filename>/usr/</filename> partition it may also be
         Verity protected, in which case the signature for the root hash may configured via a
         <term><varname>MountAPIVFS=</varname></term>
 
         <listitem><para>Takes a boolean argument. If on, a private mount namespace for the unit's processes is created
-        and the API file systems <filename>/proc</filename>, <filename>/sys</filename>, and <filename>/dev</filename>
+        and the API file systems <filename>/proc/</filename>, <filename>/sys/</filename>, and <filename>/dev/</filename>
         are mounted inside of it, unless they are already mounted. Note that this option has no effect unless used in
         conjunction with <varname>RootDirectory=</varname>/<varname>RootImage=</varname> as these three mounts are
         generally mounted in the host anyway, and unless the root directory is changed, the private mount namespace
-        will be a 1:1 copy of the host's, and include these three mounts. Note that the <filename>/dev</filename> file
+        will be a 1:1 copy of the host's, and include these three mounts. Note that the <filename>/dev/</filename> file
         system of the host is bind mounted if this option is used without <varname>PrivateDevices=</varname>. To run
         the service with a private, minimal version of <filename>/dev/</filename>, combine this option with
         <varname>PrivateDevices=</varname>.</para>
@@ -681,7 +686,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <listitem><para>Takes a profile name as argument. The process executed by the unit will switch to
         this profile when started. Profiles must already be loaded in the kernel, or the unit will fail. If
         prefixed by <literal>-</literal>, all errors will be ignored. This setting has no effect if AppArmor
-        is not enabled. This setting not affect commands prefixed with <literal>+</literal>.</para>
+        is not enabled. This setting does not affect commands prefixed with <literal>+</literal>.</para>
         </listitem>
       </varlistentry>
 
@@ -1008,7 +1013,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
         <listitem><para>Sets the CPU scheduling policy for executed processes. Takes one of <option>other</option>,
         <option>batch</option>, <option>idle</option>, <option>fifo</option> or <option>rr</option>. See
-        <citerefentry><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+        <citerefentry project='man-pages'><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
         details.</para></listitem>
       </varlistentry>
 
@@ -1018,17 +1023,19 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <listitem><para>Sets the CPU scheduling priority for executed processes. The available priority range depends
         on the selected CPU scheduling policy (see above). For real-time scheduling policies an integer between 1
         (lowest priority) and 99 (highest priority) can be used. See
-        <citerefentry><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+        <citerefentry project='man-pages'><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
         details. </para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>CPUSchedulingResetOnFork=</varname></term>
 
-        <listitem><para>Takes a boolean argument. If true, elevated CPU scheduling priorities and policies will be
-        reset when the executed processes fork, and can hence not leak into child processes. See
-        <citerefentry><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
-        details. Defaults to false.</para></listitem>
+        <listitem><para>Takes a boolean argument. If true, elevated CPU scheduling priorities and policies
+        will be reset when the executed processes call
+        <citerefentry project='man-pages'><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
+        and can hence not leak into child processes. See
+        <citerefentry project='man-pages'><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        for details. Defaults to false.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1040,7 +1047,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         are specified by the lower and upper CPU indices separated by a dash. This option may be specified more than
         once, in which case the specified CPU affinity masks are merged. If the empty string is assigned, the mask
         is reset, all assignments prior to this will have no effect. See
-        <citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+        <citerefentry project='man-pages'><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
         details.</para></listitem>
       </varlistentry>
 
@@ -1116,12 +1123,12 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <term><varname>ProtectSystem=</varname></term>
 
         <listitem><para>Takes a boolean argument or the special values <literal>full</literal> or
-        <literal>strict</literal>. If true, mounts the <filename>/usr</filename> and the boot loader
+        <literal>strict</literal>. If true, mounts the <filename>/usr/</filename> and the boot loader
         directories (<filename>/boot</filename> and <filename>/efi</filename>) read-only for processes
-        invoked by this unit. If set to <literal>full</literal>, the <filename>/etc</filename> directory is
+        invoked by this unit. If set to <literal>full</literal>, the <filename>/etc/</filename> directory is
         mounted read-only, too. If set to <literal>strict</literal> the entire file system hierarchy is
-        mounted read-only, except for the API file system subtrees <filename>/dev</filename>,
-        <filename>/proc</filename> and <filename>/sys</filename> (protect these directories using
+        mounted read-only, except for the API file system subtrees <filename>/dev/</filename>,
+        <filename>/proc/</filename> and <filename>/sys/</filename> (protect these directories using
         <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
         <varname>ProtectControlGroups=</varname>). This setting ensures that any modification of the vendor-supplied
         operating system (and optionally its configuration, and local mounts) is prohibited for the service.  It is
@@ -1137,7 +1144,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <term><varname>ProtectHome=</varname></term>
 
         <listitem><para>Takes a boolean argument or the special values <literal>read-only</literal> or
-        <literal>tmpfs</literal>. If true, the directories <filename>/home</filename>,
+        <literal>tmpfs</literal>. If true, the directories <filename>/home/</filename>,
         <filename>/root</filename>, and <filename>/run/user</filename> are made inaccessible and empty for
         processes invoked by this unit. If set to <literal>read-only</literal>, the three directories are
         made read-only instead. If set to <literal>tmpfs</literal>, temporary file systems are mounted on the
@@ -1167,12 +1174,12 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <term><varname>LogsDirectory=</varname></term>
         <term><varname>ConfigurationDirectory=</varname></term>
 
-        <listitem><para>These options take a whitespace-separated list of directory names. The specified directory
-        names must be relative, and may not include <literal>..</literal>. If set, one or more
-        directories by the specified names will be created (including their parents) below the locations
-        defined in the following table, when the unit is started. Also, the corresponding environment variable
-        is defined with the full path of directories. If multiple directories are set, then in the environment variable
-        the paths are concatenated with colon (<literal>:</literal>).</para>
+        <listitem><para>These options take a whitespace-separated list of directory names. The specified
+        directory names must be relative, and may not include <literal>..</literal>. If set, when the unit is
+        started, one or more directories by the specified names will be created (including their parents)
+        below the locations defined in the following table. Also, the corresponding environment variable will
+        be defined with the full paths of the directories. If multiple directories are set, then in the
+        environment variable the paths are concatenated with colon (<literal>:</literal>).</para>
         <table>
           <title>Automatic directory creation and environment variables</title>
           <tgroup cols='4'>
@@ -1254,13 +1261,13 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
         <para>Use <varname>RuntimeDirectory=</varname> to manage one or more runtime directories for the unit and bind
         their lifetime to the daemon runtime. This is particularly useful for unprivileged daemons that cannot create
-        runtime directories in <filename>/run</filename> due to lack of privileges, and to make sure the runtime
+        runtime directories in <filename>/run/</filename> due to lack of privileges, and to make sure the runtime
         directory is cleaned up automatically after use. For runtime directories that require more complex or different
         configuration or lifetime guarantees, please consider using
         <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
         <para>The directories defined by these options are always created under the standard paths used by systemd
-        (<filename>/var</filename>, <filename>/run</filename>, <filename>/etc</filename>, …). If the service needs
+        (<filename>/var/</filename>, <filename>/run/</filename>, <filename>/etc/</filename>, …). If the service needs
         directories in a different location, a different mechanism has to be used to create them.</para>
 
         <para><citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> provides
@@ -1275,7 +1282,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
         <para>Example: if a system service unit has the following,
         <programlisting>RuntimeDirectory=foo/bar baz</programlisting>
-        the service manager creates <filename>/run/foo</filename> (if it does not exist),
+        the service manager creates <filename index='false'>/run/foo</filename> (if it does not exist),
 
         <filename index='false'>/run/foo/bar</filename>, and <filename index='false'>/run/baz</filename>. The
         directories <filename index='false'>/run/foo/bar</filename> and
@@ -1314,7 +1321,7 @@ StateDirectory=aaa/bbb ccc</programlisting>
         and manually restarted. Here, the automatic restart means the operation specified in
         <varname>Restart=</varname>, and manual restart means the one triggered by <command>systemctl restart
         foo.service</command>. If set to <option>yes</option>, then the directories are not removed when the service is
-        stopped. Note that since the runtime directory <filename>/run</filename> is a mount point of
+        stopped. Note that since the runtime directory <filename>/run/</filename> is a mount point of
         <literal>tmpfs</literal>, then for system services the directories specified in
         <varname>RuntimeDirectory=</varname> are removed when the system is rebooted.</para></listitem>
       </varlistentry>
@@ -1334,10 +1341,10 @@ StateDirectory=aaa/bbb ccc</programlisting>
         <term><varname>ReadOnlyPaths=</varname></term>
         <term><varname>InaccessiblePaths=</varname></term>
 
-        <listitem><para>Sets up a new file system namespace for executed processes. These options may be used to limit
-        access a process might have to the file system hierarchy. Each setting takes a space-separated list of paths
-        relative to the host's root directory (i.e. the system running the service manager).  Note that if paths
-        contain symlinks, they are resolved relative to the root directory set with
+        <listitem><para>Sets up a new file system namespace for executed processes. These options may be used
+        to limit access a process has to the file system. Each setting takes a space-separated list of paths
+        relative to the host's root directory (i.e. the system running the service manager). Note that if
+        paths contain symlinks, they are resolved relative to the root directory set with
         <varname>RootDirectory=</varname>/<varname>RootImage=</varname>.</para>
 
         <para>Paths listed in <varname>ReadWritePaths=</varname> are accessible from within the namespace
@@ -1404,7 +1411,7 @@ StateDirectory=aaa/bbb ccc</programlisting>
         <para>Example: if a unit has the following,
         <programlisting>TemporaryFileSystem=/var:ro
 BindReadOnlyPaths=/var/lib/systemd</programlisting>
-        then the invoked processes by the unit cannot see any files or directories under <filename>/var</filename> except for
+        then the invoked processes by the unit cannot see any files or directories under <filename>/var/</filename> except for
         <filename>/var/lib/systemd</filename> or its contents.</para>
 
         <xi:include href="system-only.xml" xpointer="singular"/></listitem>
@@ -1413,20 +1420,22 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
       <varlistentry>
         <term><varname>PrivateTmp=</varname></term>
 
-        <listitem><para>Takes a boolean argument. If true, sets up a new file system namespace for the executed
-        processes and mounts private <filename>/tmp/</filename> and <filename>/var/tmp/</filename> directories inside it
-        that are not shared by processes outside of the namespace. This is useful to secure access to temporary files of
-        the process, but makes sharing between processes via <filename>/tmp</filename> or <filename>/var/tmp</filename>
-        impossible. If this is enabled, all temporary files created by a service in these directories will be removed
-        after the service is stopped.  Defaults to false. It is possible to run two or more units within the same
-        private <filename>/tmp</filename> and <filename>/var/tmp</filename> namespace by using the
+        <listitem><para>Takes a boolean argument. If true, sets up a new file system namespace for the
+        executed processes and mounts private <filename>/tmp/</filename> and <filename>/var/tmp/</filename>
+        directories inside it that are not shared by processes outside of the namespace. This is useful to
+        secure access to temporary files of the process, but makes sharing between processes via
+        <filename>/tmp/</filename> or <filename>/var/tmp/</filename> impossible. If this is enabled, all
+        temporary files created by a service in these directories will be removed after the service is
+        stopped. Defaults to false. It is possible to run two or more units within the same private
+        <filename>/tmp/</filename> and <filename>/var/tmp/</filename> namespace by using the
         <varname>JoinsNamespaceOf=</varname> directive, see
         <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details. This setting is implied if <varname>DynamicUser=</varname> is set. For this setting the same
-        restrictions regarding mount propagation and privileges apply as for <varname>ReadOnlyPaths=</varname> and
-        related calls, see above. Enabling this setting has the side effect of adding <varname>Requires=</varname> and
-        <varname>After=</varname> dependencies on all mount units necessary to access <filename>/tmp</filename> and
-        <filename>/var/tmp</filename>. Moreover an implicitly <varname>After=</varname> ordering on
+        restrictions regarding mount propagation and privileges apply as for
+        <varname>ReadOnlyPaths=</varname> and related calls, see above. Enabling this setting has the side
+        effect of adding <varname>Requires=</varname> and <varname>After=</varname> dependencies on all mount
+        units necessary to access <filename>/tmp/</filename> and <filename>/var/tmp/</filename>. Moreover an
+        implicitly <varname>After=</varname> ordering on
         <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         is added.</para>
 
@@ -1440,7 +1449,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
       <varlistentry>
         <term><varname>PrivateDevices=</varname></term>
 
-        <listitem><para>Takes a boolean argument. If true, sets up a new <filename>/dev</filename> mount for the
+        <listitem><para>Takes a boolean argument. If true, sets up a new <filename>/dev/</filename> mount for the
         executed processes and only adds API pseudo devices such as <filename>/dev/null</filename>,
         <filename>/dev/zero</filename> or <filename>/dev/random</filename> (as well as the pseudo TTY subsystem) to it,
         but no physical devices such as <filename>/dev/sda</filename>, system memory <filename>/dev/mem</filename>,
@@ -1453,7 +1462,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         for details). Note that using this setting will disconnect propagation of mounts from the service to the host
         (propagation in the opposite direction continues to work).  This means that this setting may not be used for
         services which shall be able to install mount points in the main mount namespace. The new
-        <filename>/dev</filename> will be mounted read-only and 'noexec'. The latter may break old programs which try
+        <filename>/dev/</filename> will be mounted read-only and 'noexec'. The latter may break old programs which try
         to set up executable memory by using
         <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> of
         <filename>/dev/zero</filename> instead of using <constant>MAP_ANON</constant>. For this setting the same
@@ -1586,7 +1595,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         <term><varname>ProtectKernelTunables=</varname></term>
 
         <listitem><para>Takes a boolean argument. If true, kernel variables accessible through
-        <filename>/proc/sys</filename>, <filename>/sys</filename>, <filename>/proc/sysrq-trigger</filename>,
+        <filename>/proc/sys/</filename>, <filename>/sys/</filename>, <filename>/proc/sysrq-trigger</filename>,
         <filename>/proc/latency_stats</filename>, <filename>/proc/acpi</filename>,
         <filename>/proc/timer_stats</filename>, <filename>/proc/fs</filename> and <filename>/proc/irq</filename> will
         be made read-only to all processes of the unit. Usually, tunable kernel variables should be initialized only at
@@ -1647,7 +1656,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
 
         <listitem><para>Takes a boolean argument. If true, the Linux Control Groups (<citerefentry
         project='man-pages'><refentrytitle>cgroups</refentrytitle><manvolnum>7</manvolnum></citerefentry>) hierarchies
-        accessible through <filename>/sys/fs/cgroup</filename> will be made read-only to all processes of the
+        accessible through <filename>/sys/fs/cgroup/</filename> will be made read-only to all processes of the
         unit. Except for container managers no services should require write access to the control groups hierarchies;
         it is hence recommended to turn this on for most services. For this setting the same restrictions regarding
         mount propagation and privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see
@@ -2020,7 +2029,7 @@ RestrictNamespaces=~cgroup net</programlisting>
               </row>
               <row>
                 <entry>@process</entry>
-                <entry>Process control, execution, namespaceing operations (<citerefentry project='man-pages'><refentrytitle>clone</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>, …)</entry>
+                <entry>Process control, execution, namespacing operations (<citerefentry project='man-pages'><refentrytitle>clone</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>, …)</entry>
               </row>
               <row>
                 <entry>@raw-io</entry>
@@ -2060,7 +2069,7 @@ RestrictNamespaces=~cgroup net</programlisting>
               </row>
               <row>
                 <entry>@known</entry>
-                <entry>All system calls defined by the kernel. This list is defined statically in systemd based on a kernel version that was available when this systmed version was released. It will become progressively more out-of-date as the kernel is updated.</entry>
+                <entry>All system calls defined by the kernel. This list is defined statically in systemd based on a kernel version that was available when this systemd version was released. It will become progressively more out-of-date as the kernel is updated.</entry>
               </row>
             </tbody>
           </tgroup>
@@ -2960,8 +2969,8 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
       <varlistentry>
         <term><varname>$LOG_NAMESPACE</varname></term>
 
-        <listitem><para>If the <varname>LogNamespace=</varname> service setting is used, contains name of the
-        selected logging namespace.</para></listitem>
+        <listitem><para>Contains the name of the selected logging namespace when the
+        <varname>LogNamespace=</varname> service setting is used.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -3623,7 +3632,8 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
         <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-        <citerefentry project='man-pages'><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+        <citerefentry project='man-pages'><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        <citerefentry project='man-pages'><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry>
       </para>
   </refsect1>
 
index babbe14e0447985a0557f401ff156662be31d185..b8d0cd578aa3939861ec5a001586c3841658a857 100644 (file)
 
     <para>Directory paths for generator output differ by priority:
     <filename>…/generator.early</filename> has priority higher than the admin
-    configuration in <filename>/etc</filename>, while
+    configuration in <filename>/etc/</filename>, while
     <filename>…/generator</filename> has lower priority than
-    <filename>/etc</filename> but higher than vendor configuration in
-    <filename>/usr</filename>, and <filename>…/generator.late</filename> has priority
+    <filename>/etc/</filename> but higher than vendor configuration in
+    <filename>/usr/</filename>, and <filename>…/generator.late</filename> has priority
     lower than all other configuration. See the next section and the discussion of
     unit load paths and unit overriding in
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
@@ -86,8 +86,8 @@
     mask a generator, thereby preventing it from running. Please note
     that the order of the two directories with the highest priority is
     reversed with respect to the unit load path, and generators in
-    <filename>/run</filename> overwrite those in
-    <filename>/etc</filename>.</para>
+    <filename>/run/</filename> overwrite those in
+    <filename>/etc/</filename>.</para>
 
     <para>After installing new generators or updating the
     configuration, <command>systemctl daemon-reload</command> may be
         in case of the system generators and
         <filename>$XDG_RUNTIME_DIR/generator.early</filename> in case of the user
         generators. Unit files placed in this directory override unit files in
-        <filename>/usr</filename>, <filename>/run</filename> and
-        <filename>/etc</filename>. This means that unit files placed in this
+        <filename>/usr/</filename>, <filename>/run/</filename> and
+        <filename>/etc/</filename>. This means that unit files placed in this
         directory take precedence over all normal configuration, both vendor and
         user/administrator.</para>
       </listitem>
         <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
         or <command>systemd</command> itself (this means: no
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>)!
-        Non-essential file systems like <filename>/var</filename> and
-        <filename>/home</filename> are mounted after generators have run. Generators
+        Non-essential file systems like <filename>/var/</filename> and
+        <filename>/home/</filename> are mounted after generators have run. Generators
         can however rely on the most basic kernel functionality to be available,
-        including a mounted <filename>/sys</filename>, <filename>/proc</filename>,
-        <filename>/dev</filename>, <filename>/usr</filename>.
+        including a mounted <filename>/sys/</filename>, <filename>/proc/</filename>,
+        <filename>/dev/</filename>, <filename>/usr/</filename>.
         </para>
       </listitem>
 
         <para>Generators may write out dynamic unit files or just hook unit files
         into other units with the usual <filename>.wants/</filename> or
         <filename>.requires/</filename> symlinks. Often, it is nicer to simply
-        instantiate a template unit file from <filename>/usr</filename> with a
+        instantiate a template unit file from <filename>/usr/</filename> with a
         generator instead of writing out entirely dynamic unit files. Of course, this
         works only if a single parameter is to be used.</para>
       </listitem>
         <orderedlist numeration="lowerroman">
           <listitem>
             <para>User configuration should override vendor configuration. This
-            (mostly) means that stuff from <filename>/etc</filename> should override
-            stuff from <filename>/usr</filename>.</para>
+            (mostly) means that stuff from <filename>/etc/</filename> should override
+            stuff from <filename>/usr/</filename>.</para>
           </listitem>
 
           <listitem>
       argv[1] as location to place the generated unit files in order to allow the
       user to override <filename>/etc/fstab</filename> with their own native unit
       files, but also to ensure that <filename>/etc/fstab</filename> overrides any
-      vendor default from <filename>/usr</filename>.</para>
+      vendor default from <filename>/usr/</filename>.</para>
 
       <para>After editing <filename>/etc/fstab</filename>, the user should invoke
       <command>systemctl daemon-reload</command>. This will re-run all generators and
index 197a468f25de8c23e2a73a359fd06b3538f5b6f3..73e3039d6e394ee6701e1cb8573a5910fca63c10 100644 (file)
           <literal>file:/</literal>, <literal>man:</literal> or <literal>info:</literal> URL.</para>
         </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>TID=</varname></term>
+        <listitem>
+          <para>The numeric thread ID (TID) the log message originates from.</para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
         <term><varname>_SYSTEMD_OWNER_UID=</varname></term>
 
         <listitem>
-          <para>The control group path in the systemd hierarchy, the
-          the systemd slice unit name, the systemd unit name, the
-          unit name in the systemd user manager (if any), the systemd
-          session ID (if any), and the owner UID of the systemd user
-          unit or systemd session (if any) of the process the journal
-          entry originates from.</para>
+          <para>The control group path in the systemd hierarchy, the systemd slice unit name, the systemd
+          unit name, the unit name in the systemd user manager (if any), the systemd session ID (if any), and
+          the owner UID of the systemd user unit or systemd session (if any) of the process the journal entry
+          originates from.</para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>_KERNEL_DEVICE=</varname></term>
         <listitem>
-          <para>The kernel device name. If the entry is associated to
-          a block device, the major and minor of the device node,
-          separated by <literal>:</literal> and prefixed by
-          <literal>b</literal>. Similar for character devices but
-          prefixed by <literal>c</literal>. For network devices, this
-          is the interface index prefixed by <literal>n</literal>. For
-          all other devices, this is the subsystem name prefixed by
-          <literal>+</literal>, followed by <literal>:</literal>,
-          followed by the kernel device name.</para>
+          <para>The kernel device name. If the entry is associated to a block device, contains the major and
+          minor numbers of the device node, separated by <literal>:</literal> and prefixed by
+          <literal>b</literal>. Similarly for character devices, but prefixed by <literal>c</literal>. For
+          network devices, this is the interface index prefixed by <literal>n</literal>. For all other
+          devices, this is the subsystem name prefixed by <literal>+</literal>, followed by
+          <literal>:</literal>, followed by the kernel device name.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>_UDEV_SYSNAME=</varname></term>
         <listitem>
           <para>The kernel device name as it shows up in the device
-          tree below <filename>/sys</filename>.</para>
+          tree below <filename>/sys/</filename>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>_UDEV_DEVNODE=</varname></term>
         <listitem>
           <para>The device node path of this device in
-          <filename>/dev</filename>.</para>
+          <filename>/dev/</filename>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>_UDEV_DEVLINK=</varname></term>
         <listitem>
           <para>Additional symlink names pointing to the device node
-          in <filename>/dev</filename>. This field is frequently set
+          in <filename>/dev/</filename>. This field is frequently set
           more than once per entry.</para>
         </listitem>
       </varlistentry>
index af69c48383c60751bb2248138c68233cc0077458..9a9ff6bd3b3dbc771a3f7b6fba8691b8bf649d64 100644 (file)
@@ -42,9 +42,9 @@
     ignored. All link files are collectively sorted and processed in
     lexical order, regardless of the directories in which they live.
     However, files with identical filenames replace each other. Files
-    in <filename>/etc</filename> have the highest priority, files in
-    <filename>/run</filename> take precedence over files with the same
-    name in <filename>/usr/lib</filename>. This can be used to
+    in <filename>/etc/</filename> have the highest priority, files in
+    <filename>/run/</filename> take precedence over files with the same
+    name in <filename>/usr/lib/</filename>. This can be used to
     override a system-supplied link file with a local file if needed.
     As a special case, an empty file (file size 0) or symlink with the
     same name pointing to <filename>/dev/null</filename> disables the
index 9e1f5d40fd9f2837aa22b1071d10983071155247..e9e2f6840844d1d1a08e2d774e64df59ef1f9ae6 100644 (file)
 
     <para>If a mount point is configured in both
     <filename>/etc/fstab</filename> and a unit file that is stored
-    below <filename>/usr</filename>, the former will take precedence.
-    If the unit file is stored below <filename>/etc</filename>, it
+    below <filename>/usr/</filename>, the former will take precedence.
+    If the unit file is stored below <filename>/etc/</filename>, it
     will take precedence. This means: native unit files take
     precedence over traditional configuration files, but this is
     superseded by the rule that configuration in
-    <filename>/etc</filename> will always take precedence over
-    configuration in <filename>/usr</filename>.</para>
+    <filename>/etc/</filename> will always take precedence over
+    configuration in <filename>/usr/</filename>.</para>
   </refsect1>
 
   <refsect1>
index 324c94dbd9fe3a95380916f4bdbc2d72dfb6694c..e894db7cd6a7457d4ea1b15ff1430c8e0d851eef 100644 (file)
           <para>SR-IOV virtual devices are named based on the name of the parent interface, with a suffix of
           <constant>v</constant> and the virtual device number, with any leading zeros removed. The bus
           number is ignored.</para>
+
+          <para>In some configurations a parent PCI bridge of a given network controller may be associated
+          with a slot. In such case we don't generate this device property to avoid possible naming conflicts.</para>
           </listitem>
         </varlistentry>
 
   <refsect1>
     <title>History</title>
 
-    <para>The following "naming schemes" have been defined:</para>
+    <para>The following "naming schemes" have been defined (which may be chosen at system boot-up time via
+    the <varname>net.naming-scheme=</varname> kernel command line switch, see above:</para>
 
     <variablelist>
         <varlistentry>
           multiple similarly named containers (who only differ in container name suffix) should be less
           likely (but still possible, since the 24bit hash value is very small).</para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><constant>v247</constant></term>
+
+          <listitem><para>If the PCI slot is assocated with PCI bridge and that has multiple child network
+          controllers then all of them might derive the same value of <varname>ID_NET_NAME_SLOT</varname>
+          property. That could cause naming conflict if the property is selected as a device name. Now, we detect the
+          situation, slot - bridge relation, and we don't produce the <varname>ID_NET_NAME_SLOT</varname> property to
+          avoid possible naming conflict.</para></listitem>
+        </varlistentry>
+
       </variablelist>
 
     <para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
index 2e716cca9c0bf8dee39af825433ca17ee2771888..a95beb6f9fa14b57616202301e7e829b9d276fd0 100644 (file)
@@ -43,9 +43,9 @@
     directory <filename>/run/systemd/network</filename> and the local administration network
     directory <filename>/etc/systemd/network</filename>. All configuration files are collectively
     sorted and processed in lexical order, regardless of the directories in which they live.
-    However, files with identical filenames replace each other. Files in <filename>/etc</filename>
-    have the highest priority, files in <filename>/run</filename> take precedence over files with
-    the same name in <filename>/usr/lib</filename>. This can be used to override a system-supplied
+    However, files with identical filenames replace each other. Files in <filename>/etc/</filename>
+    have the highest priority, files in <filename>/run/</filename> take precedence over files with
+    the same name in <filename>/usr/lib/</filename>. This can be used to override a system-supplied
     configuration file with a local file if needed. As a special case, an empty file (file size 0)
     or symlink with the same name pointing to <filename>/dev/null</filename> disables the
     configuration file entirely (it is "masked").</para>
     <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
     directories can be placed in <filename>/usr/lib/systemd/network</filename> or
     <filename>/run/systemd/network</filename> directories. Drop-in files in
-    <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
-    take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
+    <filename>/etc/</filename> take precedence over those in <filename>/run/</filename> which in turn
+    take precedence over those in <filename>/usr/lib/</filename>. Drop-in files under any of these
     directories take precedence over the main netdev file wherever located. (Of course, since
-    <filename>/run</filename> is temporary and <filename>/usr/lib</filename> is for vendors, it is
+    <filename>/run/</filename> is temporary and <filename>/usr/lib/</filename> is for vendors, it is
     unlikely drop-ins should be used in either of those places.)</para>
   </refsect1>
 
   <refsect1>
     <title>[MACVTAP] Section Options</title>
 
-    <para>The [MACVTAP] section applies for
-    netdevs of kind <literal>macvtap</literal> and accepts the
-    same key as [MACVLAN].</para>
+    <para>The [MACVTAP] section applies for netdevs of kind <literal>macvtap</literal> and accepts the same
+    keys as [MACVLAN].</para>
   </refsect1>
 
   <refsect1>
   <refsect1>
     <title>[IPVTAP] Section Options</title>
 
-    <para>The [IPVTAP] section only applies for
-    netdevs of kind <literal>ipvtap</literal> and accepts the
-    same key as [IPVLAN].</para>
+    <para>The [IPVTAP] section only applies for netdevs of kind <literal>ipvtap</literal> and accepts the
+    same keys as [IPVLAN].</para>
   </refsect1>
 
   <refsect1>
       <varlistentry>
         <term><varname>DestinationPort=</varname></term>
         <listitem>
-          <para>Configures the default destination UDP port on a per-device basis.
-          If destination port is not specified then Linux kernel default will be used.
-          Set destination port 4789 to get the IANA assigned value. If not set or if the
-          destination port is assigned the empty string the default port of 4789 is used.</para>
+          <para>Configures the default destination UDP port. If the destination port is not specified then
+          Linux kernel default will be used. Set to 4789 to get the IANA assigned value.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>PortRange=</varname></term>
         <listitem>
-          <para>Configures VXLAN port range. VXLAN bases source
-          UDP port based on flow to help the receiver to be able
-          to load balance based on outer header flow. It
-          restricts the port range to the normal UDP local
-          ports, and allows overriding via configuration.</para>
+          <para>Configures the source port range for the VXLAN. The kernel assigns the source UDP port based
+          on the flow to help the receiver to do load balancing. When this option is not set, the normal
+          range of local UDP ports is used.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>IPDoNotFragment=</varname></term>
         <listitem>
-          <para>Accepts the same key in [VXLAN] section.</para>
+          <para>Accepts the same key as in [VXLAN] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>PeerTunnelId=</varname></term>
         <listitem>
           <para>Specifies the peer tunnel id. Takes a number in the range 1—4294967295. The value used must
-          match the <literal>PeerTunnelId=</literal> value being used at the peer. This setting is
-          compulsory.</para>
+          match the <literal>TunnelId=</literal> value being used at the peer. This setting is compulsory.
+          </para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>Port=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecReceiveChannel] section.</para>
+          <para>Accepts the same key as in [MACsecReceiveChannel] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>MACAddress=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecReceiveChannel] section.</para>
+          <para>Accepts the same key as in [MACsecReceiveChannel] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>PacketNumber=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecTransmitAssociation] section.</para>
+          <para>Accepts the same key as in [MACsecTransmitAssociation] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>KeyId=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecTransmitAssociation] section.</para>
+          <para>Accepts the same key as in [MACsecTransmitAssociation] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Key=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecTransmitAssociation] section.</para>
+          <para>Accepts the same key as in [MACsecTransmitAssociation] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>KeyFile=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecTransmitAssociation] section.</para>
+          <para>Accepts the same key as in [MACsecTransmitAssociation] section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Activate=</varname></term>
         <listitem>
-          <para>Accepts the same key in [MACsecTransmitAssociation] section.</para>
+          <para>Accepts the same key as in [MACsecTransmitAssociation] section.</para>
         </listitem>
       </varlistentry>
     </variablelist>
           <para>Specifies the encapsulation mechanism used to store networking packets of various protocols
           inside the UDP packets. Supports the following values:
 
-          <literal>FooOverUDP</literal> provides the simplest no frills model of UDP encapsulation, it simply
+          <literal>FooOverUDP</literal> provides the simplest no-frills model of UDP encapsulation, it simply
           encapsulates packets directly in the UDP payload. <literal>GenericUDPEncapsulation</literal> is a
           generic and extensible encapsulation, it allows encapsulation of packets for any IP protocol and
           optional data as part of the encapsulation. For more detailed information see <ulink
       <varlistentry>
         <term><varname>Port=</varname></term>
         <listitem>
-          <para>Specifies the port number, where the IP encapsulation packets will arrive. Please take note
-          that the packets will arrive with the encapsulation will be removed. Then they will be manually fed
-          back into the network stack, and sent ahead for delivery to the real destination. This option is
-          mandatory.</para>
+          <para>Specifies the port number where the encapsulated packets will arrive. Those packets will be
+          removed and manually fed back into the network stack with the encapsulation removed to be sent to
+          the real destination. This option is mandatory.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
index 02d56480b5315308a49c2b15c13d533b1387984f..1eb8274e8325aa149de736883f83f7f5958bab56 100644 (file)
@@ -43,9 +43,9 @@
     <filename>/run/systemd/network</filename> and the local administration network directory
     <filename>/etc/systemd/network</filename>. All configuration files are collectively sorted and processed
     in lexical order, regardless of the directories in which they live. However, files with identical
-    filenames replace each other. Files in <filename>/etc</filename> have the highest priority, files in
-    <filename>/run</filename> take precedence over files with the same name under
-    <filename>/usr</filename>. This can be used to override a system-supplied configuration file with a local
+    filenames replace each other. Files in <filename>/etc/</filename> have the highest priority, files in
+    <filename>/run/</filename> take precedence over files with the same name under
+    <filename>/usr/</filename>. This can be used to override a system-supplied configuration file with a local
     file if needed. As a special case, an empty file (file size 0) or symlink with the same name pointing to
     <filename>/dev/null</filename> disables the configuration file entirely (it is "masked").</para>
 
@@ -58,8 +58,8 @@
     <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
     directories can be placed in <filename>/usr/lib/systemd/network</filename> or
     <filename>/run/systemd/network</filename> directories. Drop-in files in
-    <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
-    take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
+    <filename>/etc/</filename> take precedence over those in <filename>/run/</filename> which in turn
+    take precedence over those in <filename>/usr/lib/</filename>. Drop-in files under any of these
     directories take precedence over the main network file wherever located.</para>
 
     <para>Note that an interface without any static IPv6 addresses configured, and neither DHCPv6
@@ -810,17 +810,23 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         </para></listitem>
         </varlistentry>
         <varlistentry>
-          <term><varname>IPv6PrefixDelegation=</varname></term>
-          <listitem><para>Whether to enable or disable Router Advertisement sending on a link.  Allowed
-          values are <literal>static</literal> which distributes prefixes as defined in the
-          [IPv6PrefixDelegation] and any [IPv6Prefix] sections, <literal>dhcpv6</literal> which requests
-          prefixes using a DHCPv6 client configured for another link and any values configured in the
-          [IPv6PrefixDelegation] section while ignoring all static prefix configuration sections,
-          <literal>yes</literal> which uses both static configuration and DHCPv6, and
-          <literal>false</literal> which turns off IPv6 prefix delegation altogether. Defaults to
-          <literal>false</literal>. See the [IPv6PrefixDelegation] and the [IPv6Prefix] sections for more
+          <term><varname>IPv6SendRA=</varname></term>
+          <listitem><para>Whether to enable or disable Router Advertisement sending on a link. Takes a
+          boolean value. When enabled, prefixes configured in [IPv6Prefix] sections and routes
+          configured in [IPv6RoutePrefix] sections are distributed as defined in the [IPv6SendRA]
+          section. If <varname>DHCPv6PrefixDelegation=</varname> is enabled, then the delegated
+          prefixes are also distributed. See <varname>DHCPv6PrefixDelegation=</varname> setting and the
+          [IPv6SendRA], [IPv6Prefix], [IPv6RoutePrefix], and [DHCPv6PrefixDelegation] sections for more
           configuration options.</para></listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>DHCPv6PrefixDelegation=</varname></term>
+          <listitem><para>Takes a boolean value. When enabled, requests prefixes using a DHCPv6 client
+          configured on another link. By default, an address within each delegated prefix will be
+          assigned, and the prefixes will be announced through IPv6 Router Advertisement when
+          <varname>IPv6SendRA=</varname> is enabled. Such default settings can be configured in
+          [DHCPv6PrefixDelegation] section.</para></listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>IPv6MTUBytes=</varname></term>
           <listitem><para>Configures IPv6 maximum transmission unit (MTU).
@@ -1282,9 +1288,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <varlistentry>
           <term><varname>Gateway=</varname></term>
           <listitem>
-            <para>Takes the gateway address or special value <literal>_dhcp</literal>. If
-            <literal>_dhcp</literal>, then the gateway address provided by DHCP (or in the IPv6 case,
-            provided by IPv6 RA) is used.</para>
+            <para>Takes the gateway address or the special values <literal>_dhcp4</literal> and
+            <literal>_ipv6ra</literal>. If <literal>_dhcp4</literal> or <literal>_ipv6ra</literal> is
+            set, then the gateway address provided by DHCPv4 or IPv6 RA is used.</para>
           </listitem>
         </varlistentry>
          <varlistentry>
@@ -1389,21 +1395,22 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <varlistentry>
           <term><varname>InitialCongestionWindow=</varname></term>
           <listitem>
-            <para>The TCP initial congestion window is used during the start of a TCP connection. During the start of a TCP
-            session, when a client requests a resource, the server's initial congestion window determines how many data bytes
-            will be sent during the initial burst of data. Takes a size in bytes between 1 and 4294967295 (2^32 - 1). The usual
-            suffixes K, M, G are supported and are understood to the base of 1024. When unset, the kernel's default will be used.
-            </para>
+            <para>The TCP initial congestion window is used during the start of a TCP connection.
+            During the start of a TCP session, when a client requests a resource, the server's initial
+            congestion window determines how many packets will be sent during the initial burst of data
+            without waiting for acknowledgement. Takes a number between 1 and 1023. Note that 100 is
+            considered an extremely large value for this option. When unset, the kernel's default
+            (typically 10) will be used.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>InitialAdvertisedReceiveWindow=</varname></term>
           <listitem>
-            <para>The TCP initial advertised receive window is the amount of receive data (in bytes) that can initially be buffered at one time
-            on a connection. The sending host can send only that amount of data before waiting for an acknowledgment and window update
-            from the receiving host. Takes a size in bytes between 1 and 4294967295 (2^32 - 1). The usual suffixes K, M, G are supported
-            and are understood to the base of 1024. When unset, the kernel's default will be used.
-            </para>
+            <para>The TCP initial advertised receive window is the amount of receive data (in bytes)
+            that can initially be buffered at one time on a connection. The sending host can send only
+            that amount of data before waiting for an acknowledgment and window update from the
+            receiving host. Takes a number between 1 and 1023. Note that 100 is considered an extremely
+            large value for this option. When unset, the kernel's default will be used.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
@@ -1548,11 +1555,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <varlistentry>
           <term><varname>MUDURL=</varname></term>
           <listitem>
-            <para>When configured, the Manufacturer Usage Descriptions (MUD) URL will be sent to the
-            DHCPv4 server. Takes an URL of length up to 255 characters. A superficial verification that
-            the string is a valid URL will be performed. DHCPv4 clients are intended to have at most one
-            MUD URL associated with them. See
-            <ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink>.</para>
+            <para>When configured, the specified Manufacturer Usage Description (MUD) URL will be sent to the
+            DHCPv4 server. Takes a URL of length up to 255 characters. A superficial verification that the
+            string is a valid URL will be performed. DHCPv4 clients are intended to have at most one MUD URL
+            associated with them. See <ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink>.
+            </para>
+
+            <para>MUD is an embedded software standard defined by the IETF that allows IoT device makers to
+            advertise device specifications, including the intended communication patterns for their device
+            when it connects to the network. The network can then use this to author a context-specific
+            access policy, so the device functions only within those parameters.</para>
           </listitem>
         </varlistentry>
 
@@ -1847,18 +1859,18 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <varlistentry>
           <term><varname>MUDURL=</varname></term>
           <listitem>
-            <para>When configured, the Manufacturer Usage Descriptions (MUD) URL will be sent to the DHCPV6 server.
-            Takes an URL of length up to 255 characters. A superficial verification that the string is a valid URL
-            will be performed. DHCPv6 clients are intended to have at most one MUD URL associated with them. See
-            <ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink>.</para>
+            <para>When configured, the specified Manufacturer Usage Description (MUD) URL will be sent to
+            the DHCPV6 server. The syntax and semantics are the same as for <varname>MUDURL=</varname> in the
+            [DHCPv4] section described above.</para>
           </listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>RequestOptions=</varname></term>
           <listitem>
-            <para>When configured, allows to set arbitrary request options in the DHCPv6 request options list and will
-            sent to the DHCPV6 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
+            <para>When configured, allows to set arbitrary request options in the DHCPv6 request options list
+            that will be sent to the DHCPV6 server. A whitespace-separated list of integers in the range
+            1..254. Defaults to unset.</para>
           </listitem>
         </varlistentry>
 
@@ -1951,9 +1963,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
 
   <refsect1>
     <title>[DHCPv6PrefixDelegation] Section Options</title>
-    <para>The [DHCPv6PrefixDelegation] section configures delegated prefix assigned by DHCPv6 server.
-    The settings in this section are used only when <varname>IPv6PrefixDelegation=</varname> setting is
-    enabled, or set to <literal>dhcp6</literal>.</para>
+    <para>The [DHCPv6PrefixDelegation] section configures delegated prefixes assigned by DHCPv6 server.
+    The settings in this section are used only when <varname>DHCPv6PrefixDelegation=</varname> setting
+    is enabled.</para>
 
     <variablelist class='network-directives'>
       <varlistentry>
@@ -1963,9 +1975,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
           delegation. You can either set "auto" (the default) or a specific subnet ID (as defined in
           <ulink url="https://tools.ietf.org/html/rfc4291#section-2.5.4">RFC 4291</ulink>, section
           2.5.4), in which case the allowed value is hexadecimal, from 0 to 0x7fffffffffffffff
-          inclusive. This option is only effective when used together with
-          <varname>IPv6PrefixDelegation=</varname> and the corresponding configuration on the upstream
-          interface.</para>
+          inclusive.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>Announce=</varname></term>
+        <listitem>
+          <para>Takes a boolean. When enabled, and <varname>IPv6SendRA=</varname> in [Network] section
+          is enabled, the delegated prefixes are distributed through the IPv6 Router Advertisement.
+          Defaults to yes.</para>
         </listitem>
       </varlistentry>
 
@@ -1973,19 +1992,22 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <term><varname>Assign=</varname></term>
         <listitem>
           <para>Takes a boolean. Specifies whether to add an address from the delegated prefixes which
-          are received from the WAN interface by the <varname>IPv6PrefixDelegation=</varname>. When
-          true (on LAN interfce), the EUI-64 algorithm will be used to form an interface identifier
-          from the delegated prefixes. Defaults to true.</para>
+          are received from the WAN interface by the DHCPv6 Prefix Delegation. When true (on LAN
+          interfce), the EUI-64 algorithm will be used by default to form an interface identifier from
+          the delegated prefixes. See also <varname>Token=</varname> setting below. Defaults to yes.
+          </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>Token=</varname></term>
         <listitem>
-          <para>Specifies an optional address generation mode for <varname>Assign=</varname>. Takes an
-          IPv6 address. When set, the lower bits of the supplied address are combined with the upper
-          bits of a delegatad prefix received from the WAN interface by the
-          <varname>IPv6PrefixDelegation=</varname> prefixes to form a complete address.</para>
+          <para>Specifies an optional address generation mode for assigning an address in each
+          delegated prefix. Takes an IPv6 address. When set, the lower bits of the supplied address is
+          combined with the upper bits of each delegatad prefix received from the WAN interface by the
+          DHCPv6 Prefix Delegation to form a complete address. When <varname>Assign=</varname> is
+          disabled, this setting is ignored. When unset, the EUI-64 algorithm will be used to form
+          addresses. Defaults to unset.</para>
         </listitem>
       </varlistentry>
     </variablelist>
@@ -2049,8 +2071,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <varlistentry>
           <term><varname>UseOnLinkPrefix=</varname></term>
           <listitem>
-            <para>When true (the default), the onlink prefix received in the Router Advertisement will be used and take
-            precedence over any statically configured ones.</para>
+            <para>When true (the default), the onlink prefix received in the Router Advertisement will be
+            used and takes precedence over any statically configured ones.</para>
           </listitem>
         </varlistentry>
 
@@ -2207,10 +2229,11 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
   </refsect1>
 
   <refsect1>
-    <title>[IPv6PrefixDelegation] Section Options</title>
-    <para>The [IPv6PrefixDelegation] section contains settings for sending IPv6 Router Advertisements and
-    whether to act as a router, if enabled via the <varname>IPv6PrefixDelegation=</varname> option described
-    above. IPv6 network prefixes are defined with one or more [IPv6Prefix] sections.</para>
+    <title>[IPv6SendRA] Section Options</title>
+    <para>The [IPv6SendRA] section contains settings for sending IPv6 Router Advertisements and whether
+    to act as a router, if enabled via the <varname>IPv6SendRA=</varname> option described above. IPv6
+    network prefixes or routes are defined with one or more [IPv6Prefix] or [IPv6RoutePrefix] sections.
+    </para>
 
     <variablelist class='network-directives'>
 
@@ -2562,19 +2585,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
   <refsect1>
     <title>[LLDP] Section Options</title>
       <para>The [LLDP] section manages the Link Layer Discovery Protocol (LLDP) and accepts the following
-      keys.</para>
+      keys:</para>
       <variablelist class='network-directives'>
         <varlistentry>
           <term><varname>MUDURL=</varname></term>
           <listitem>
-            <para>Controls support for Ethernet LLDP packet's Manufacturer Usage Description (MUD). MUD is an embedded software
-            standard defined by the IETF that allows IoT Device makers to advertise device specifications, including the intended
-            communication patterns for their device when it connects to the network. The network can then use this intent to author
-            a context-specific access policy, so the device functions only within those parameters. Takes an URL of length up to 255
-            characters. A superficial verification that the string is a valid URL
-            will be performed. See
-            <ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink> for details. The MUD URL received
-            from the LLDP packets will be saved at the state files and can be read via
+            <para>When configured, the specified Manufacturer Usage Descriptions (MUD) URL will be sent in
+            LLDP packets. The syntax and semantics are the same as for <varname>MUDURL=</varname> in the
+            [DHCPv4] section described above.</para>
+
+            <para>The MUD URLs received via LLDP packets are saved and can be read using the
             <function>sd_lldp_neighbor_get_mud_url()</function> function.</para>
           </listitem>
         </varlistentry>
@@ -2892,11 +2912,11 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
       <varlistentry>
         <term><varname>LimitBytes=</varname></term>
         <listitem>
-          <para>Specifies the hard limit on the FIFO size in bytes. The size limit (a buffer size) to prevent
-          it from overflowing in case it is unable to dequeue packets as quickly as it receives them. When
-          this limit is reached, incoming packets are dropped. When suffixed with K, M, or G, the specified
-          size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. Defaults
-          to unset and kernel's default is used.</para>
+          <para>Specifies the hard limit in bytes on the FIFO buffer size. The size limit prevents overflow
+          in case the kernel is unable to dequeue packets as quickly as it receives them. When this limit is
+          reached, incoming packets are dropped. When suffixed with K, M, or G, the specified size is parsed
+          as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. Defaults to unset and
+          kernel default is used.</para>
         </listitem>
       </varlistentry>
     </variablelist>
@@ -3103,13 +3123,12 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
       <varlistentry>
         <term><varname>PriorityMap=</varname></term>
         <listitem>
-          <para>The priority map maps the priority of a packet to a band. The argument is a white-space
-          separated list of numbers. The first number indicates which band the packets with priority
-          0 should be put to, the second is for priority 1, and so on. There can be up to 16 numbers in
-          the list. If there are fewer, the default band that traffic with one of the unmentioned
-          priorities goes to is the last one. Each band number must be 0..255. This setting can be
-          specified multiple times. If an empty string is assigned, then the all previous assignments
-          are cleared.</para>
+          <para>The priority map maps the priority of a packet to a band. The argument is a whitespace
+          separated list of numbers. The first number indicates which band the packets with priority 0 should
+          be put to, the second is for priority 1, and so on. There can be up to 16 numbers in the list. If
+          there are fewer, the default band that traffic with one of the unmentioned priorities goes to is
+          the last one. Each band number must be in the range 0..255. This setting can be specified multiple
+          times. If an empty string is assigned, then the all previous assignments are cleared.</para>
         </listitem>
       </varlistentry>
     </variablelist>
@@ -3584,10 +3603,13 @@ DHCP=ipv6</programlisting>
 Name=enp2s0
 
 [Network]
-IPv6PrefixDelegation=dhcpv6</programlisting>
+IPv6SendRA=yes
+DHCPv6PrefixDelegation=yes</programlisting>
 
-      <para>This will enable IPv6 PD on the interface enp1s0 as an upstream interface where the
-      DHCPv6 client is running and enp2s0 as a downstream interface where the prefix is delegated to.</para>
+      <para>This will enable DHCPv6-PD on the interface enp1s0 as an upstream interface where the
+      DHCPv6 client is running and enp2s0 as a downstream interface where the prefix is delegated to.
+      The delegated prefixes are distributed by IPv6 Router Advertisement on the downstream network.
+      </para>
     </example>
 
     <example>
index 81a37f67898c649bc1d42da5fe6b0460167f28e8..242448aa041346bfb2959bb1dc11dd72b2eda9bb 100644 (file)
@@ -44,7 +44,7 @@
         created that points to <filename index="false">/var/lib/system-update</filename> (or
         wherever the directory with the upgrade files is located) and the system is rebooted. This
         symlink is in the root directory, since we need to check for it very early at boot, at a
-        time where <filename>/var</filename> is not available yet.</para>
+        time where <filename>/var/</filename> is not available yet.</para>
       </listitem>
 
       <listitem>
         script exits uncleanly (by non-zero error code, or signal/coredump). If your script succeeds
         you should trigger the reboot in your own code, for example by invoking logind's
         <command>Reboot()</command> call or calling <command>systemctl reboot</command>. See
-        <ulink url="https://www.freedesktop.org/wiki/Software/systemd/logind">logind dbus API</ulink>
-        for details.</para>
+        <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for details about the logind D-Bus API.</para>
       </listitem>
 
       <listitem>
index d72f9048e7c00ab3d8f72d07c4ae7132d433ca74..b40fa86145451a23a85a968edd54d7f9b7e733f1 100644 (file)
@@ -869,6 +869,49 @@ DeviceAllow=/dev/loop-control
           <xi:include href="supported-controllers.xml"  xpointer="controllers-text" />
         </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>ManagedOOMSwap=auto|kill</varname></term>
+        <term><varname>ManagedOOMMemoryPressure=auto|kill</varname></term>
+
+        <listitem>
+          <para>Specifies how
+          <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+          will act on this unit's cgroups. Defaults to <option>auto</option>.</para>
+
+          <para>When set to <option>kill</option>, <command>systemd-oomd</command> will actively monitor this unit's
+          cgroup metrics to decide whether it needs to act. If the cgroup passes the limits set by
+          <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> or its
+          overrides, <command>systemd-oomd</command> will send a <constant>SIGKILL</constant> to all of the processes
+          under the chosen candidate cgroup. Note that only descendant cgroups can be eligible candidates for killing;
+          the unit that set its property to <option>kill</option> is not a candidate (unless one of its ancestors set
+          their property to <option>kill</option>). You can find more details on candidates and kill behavior at
+          <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+          and <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Setting
+          either of these properties to <option>kill</option> will also automatically acquire
+          <varname>After=</varname> and <varname>Wants=</varname> dependencies on
+          <filename>systemd-oomd.service</filename> unless <varname>DefaultDependencies=no</varname>.
+        </para>
+
+          <para>When set to <option>auto</option>, <command>systemd-oomd</command> will not actively use this cgroup's
+          data for monitoring and detection. However, if an ancestor cgroup has one of these properties set to
+          <option>kill</option>, a unit with <option>auto</option> can still be an eligible candidate for
+          <command>systemd-oomd</command> to act on.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>ManagedOOMMemoryPressureLimitPercent=</varname></term>
+
+        <listitem>
+          <para>Overrides the default memory pressure limit set by
+          <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for this unit
+          (cgroup). Takes a percentage value between 0% and 100%, inclusive. This property is ignored unless
+          <varname>ManagedOOMMemoryPressure=</varname><option>kill</option>. Defaults to 0%, which means use the
+          default set by <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
@@ -1030,6 +1073,7 @@ DeviceAllow=/dev/loop-control
       <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       The documentation for control groups and specific controllers in the Linux kernel:
       <ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink>.
     </para>
index d11e37da840bac2783ffa69deb5e10e326e0565d..5bb13fcfe75c21a28023473144e634a77fb74f97 100644 (file)
             has <varname>RemainAfterExit=</varname> not set) it will not show up as started afterwards, but
             as dead.</para></listitem>
 
-            <listitem><para>Behavior of <option>dbus</option> is similar to <option>simple</option>; however, it is
-            expected that the service acquires a name on the D-Bus bus, as configured by
-            <varname>BusName=</varname>. systemd will proceed with starting follow-up units after the D-Bus bus name
-            has been acquired. Service units with this option configured implicitly gain dependencies on the
-            <filename>dbus.socket</filename> unit. This type is the default if <varname>BusName=</varname> is
-            specified.</para></listitem>
+            <listitem><para>Behavior of <option>dbus</option> is similar to <option>simple</option>; however,
+            it is expected that the service acquires a name on the D-Bus bus, as configured by
+            <varname>BusName=</varname>. systemd will proceed with starting follow-up units after the D-Bus
+            bus name has been acquired. Service units with this option configured implicitly gain
+            dependencies on the <filename>dbus.socket</filename> unit. This type is the default if
+            <varname>BusName=</varname> is specified. A service unit of this type is considered to be in the
+            activating state until the specified bus name is acquired. It is considered activated while the
+            bus name is taken. Once the bus name is released the service is considered being no longer
+            functional which has the effect that the service manager attempts to terminate any remaining
+            processes belonging to the service. Services that drop their bus name as part of their shutdown
+            logic thus should be prepared to receive a <constant>SIGTERM</constant> (or whichever signal is
+            configured in <varname>KillSignal=</varname>) as result.</para></listitem>
 
             <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however, it is
             expected that the service sends a notification message via
         <literal>FDSTORE=1</literal> messages. This is useful for implementing services that can restart
         after an explicit request or a crash without losing state. Any open sockets and other file
         descriptors which should not be closed during the restart may be stored this way. Application state
-        can either be serialized to a file in <filename>/run</filename>, or better, stored in a
+        can either be serialized to a file in <filename>/run/</filename>, or better, stored in a
         <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         memory file descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service
         manager. All file descriptors passed to the service manager from a specific service are passed back
     into words, and afterwards removed.</para>
 
     <para>If the command is not a full (absolute) path, it will be resolved to a full path using a
-    fixed search path determinted at compilation time. Searched directories include
+    fixed search path determined at compilation time. Searched directories include
     <filename>/usr/local/bin/</filename>, <filename>/usr/bin/</filename>, <filename>/bin/</filename>
     on systems using split <filename>/usr/bin/</filename> and <filename>/bin/</filename>
     directories, and their <filename>sbin/</filename> counterparts on systems using split
@@ -1307,7 +1313,7 @@ ls</programlisting>
       <title>Simple service</title>
 
       <para>The following unit file creates a service that will
-      execute <filename>/usr/sbin/foo-daemon</filename>. Since no
+      execute <filename index="false">/usr/sbin/foo-daemon</filename>. Since no
       <varname>Type=</varname> is specified, the default
       <varname>Type=</varname><option>simple</option> will be assumed.
       systemd will assume the unit to be started immediately after the
index ba0ad1d36e7cf3e25e62e02b15da77254c77166f..079cdf00523617ba8ef109b7e38929a8a9ee32dd 100644 (file)
         argument. Behavior otherwise is very similar to the
         <varname>ListenFIFO=</varname> directive above. Use this to
         open character device nodes as well as special files in
-        <filename>/proc</filename> and
-        <filename>/sys</filename>.</para></listitem>
+        <filename>/proc/</filename> and
+        <filename>/sys/</filename>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         url="https://www.kernel.org/doc/Documentation/usb/functionfs.txt">USB
         FunctionFS</ulink> endpoints location to listen on, for
         implementation of USB gadget functions. This expects an
-        absolute file system path of FunctionFS mount point as the argument.
+        absolute file system path of FunctionFS mount point as the argument.
         Behavior otherwise is very similar to the <varname>ListenFIFO=</varname>
         directive above. Use this to open the FunctionFS endpoint
         <filename>ep0</filename>. When using this option, the
index a948969a8f8efc07ad2700971c7fc8916933ec76..fe40da7fbe25568dfe35de9e2a88997dbc19ef47 100644 (file)
@@ -32,6 +32,7 @@
     <filename>emergency.target</filename>,
     <filename>exit.target</filename>,
     <filename>final.target</filename>,
+    <filename>first-boot-complete.target</filename>,
     <filename>getty.target</filename>,
     <filename>getty-pre.target</filename>,
     <filename>graphical.target</filename>,
@@ -40,6 +41,7 @@
     <filename>hybrid-sleep.target</filename>,
     <filename>suspend-then-hibernate.target</filename>,
     <filename>initrd.target</filename>,
+    <filename>initrd-cryptsetup.target</filename>,
     <filename>initrd-fs.target</filename>,
     <filename>initrd-root-device.target</filename>,
     <filename>initrd-root-fs.target</filename>,
             <varname>DefaultDependencies=no</varname>).</para>
 
             <para>Usually, this should pull-in all local mount points plus
-            <filename>/var</filename>, <filename>/tmp</filename> and
-            <filename>/var/tmp</filename>, swap devices, sockets, timers,
+            <filename>/var/</filename>, <filename>/tmp/</filename> and
+            <filename>/var/tmp/</filename>, swap devices, sockets, timers,
             path units and other basic initialization necessary for general
             purpose daemons. The mentioned mount points are special cased
             to allow them to be remote.
         <varlistentry>
           <term><filename>cryptsetup.target</filename></term>
           <listitem>
-            <para>A target that pulls in setup services for all
-            encrypted block devices.</para>
+            <para>A target that pulls in setup services for local encrypted block devices.
+            See <filename>remote-cryptsetup.target</filename> below for the equivalent target for remote
+            volumes, and <filename>initrd-cryptsetup.target</filename> below for the equivalent target in the
+            initrd.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
         <varlistentry>
           <term><filename>initrd.target</filename></term>
           <listitem>
-            <para>This is the default target in the initramfs, similar to <filename>default.target</filename>
+            <para>This is the default target in the initrd, similar to <filename>default.target</filename>
             in the main system. It is used to mount the real root and transition to it. See
             <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
             more discussion.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><filename>initrd-cryptsetup.target</filename></term>
+          <listitem>
+            <para>A target that pulls in setup services for all encrypted block devices. See
+            <filename>cryptsetup.target</filename> and <filename>remote-cryptsetup.target</filename> for the
+            equivalent targets in the real root.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><filename>initrd-fs.target</filename></term>
           <listitem>
             <para>Similar to <filename>cryptsetup.target</filename>, but for encrypted
             devices which are accessed over the network. It is used for
             <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-            entries marked with <option>_netdev</option>.</para>
+            entries marked with <option>_netdev</option>.
+            See <filename>cryptsetup.target</filename> for the equivalent target for local volumes, and
+            <filename>initrd-cryptsetup.target</filename> for the equivalent target in the initrd.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           pulled in via a <option>Wants=</option> dependency of the storage daemon and thus generally not be
           part of any transaction unless a storage daemon is used. The instance name for instances of this
           template unit must be a properly escaped block device node path, e.g.
-          <filename>blockdev@dev-mapper-foobar.target</filename> for the storage device
-          <filename>/dev/mapper/foobar</filename>.</para></listitem>
+          <filename index="false">blockdev@dev-mapper-foobar.target</filename> for the storage device
+          <filename index="false">/dev/mapper/foobar</filename>.</para></listitem>
         </varlistentry>
         <varlistentry>
           <term><filename>cryptsetup-pre.target</filename></term>
             stopped.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><filename>first-boot-complete.target</filename></term>
+          <listitem>
+            <para>This passive target is intended as a synchronization point for units that need to run once
+            during the first boot.  Only after all units ordered before this target have finished, will the
+            <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+            be committed to disk, marking the first boot as completed.  If the boot is aborted at any time
+            before that, the next boot will re-run any units with <varname>ConditionFirstBoot=yes</varname>.
+            </para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><filename>getty-pre.target</filename></term>
           <listitem>
             <citerefentry><refentrytitle>systemd-xdg-autostart-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
             for the XDG desktop files in autostart directories.
             Desktop Environments can opt-in to use this service by adding a <varname>Wants=</varname>
-            dependency on <literal>xdg-desktop-autostart.target</literal></para>.
+            dependency on <literal>xdg-desktop-autostart.target</literal>.</para>
           </listitem>
         </varlistentry>
       </variablelist>
index 80057e27e3364e77a7b602e2e280161bc047ba30..4b8e515fe2a6d6d74b89197653b7d844ace88e7c 100644 (file)
 <filename>$XDG_RUNTIME_DIR/systemd/user.control/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/transient/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/generator.early/*</filename>
-<filename>~/.config/systemd/user/*</filename>
+<filename>$XDG_CONFIG_HOME/systemd/user/*</filename>
+<filename>$XDG_CONFIG_DIRS/systemd/user/*</filename>
 <filename>/etc/systemd/user/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>
 <filename>/run/systemd/user/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/generator/*</filename>
-<filename>~/.local/share/systemd/user/*</filename>
+<filename>$XDG_DATA_HOME/systemd/user/*</filename>
+<filename>$XDG_DATA_DIRS/systemd/user/*</filename>
 <filename index='false'>…</filename>
 <filename>/usr/lib/systemd/user/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/generator.late/*</filename></literallayout></para>
 
     <para>In addition to <filename>/etc/systemd/system</filename>, the drop-in <literal>.d/</literal>
     directories for system services can be placed in <filename>/usr/lib/systemd/system</filename> or
-    <filename>/run/systemd/system</filename> directories. Drop-in files in <filename>/etc</filename>
-    take precedence over those in <filename>/run</filename> which in turn take precedence over those
-    in <filename>/usr/lib</filename>. Drop-in files under any of these directories take precedence
+    <filename>/run/systemd/system</filename> directories. Drop-in files in <filename>/etc/</filename>
+    take precedence over those in <filename>/run/</filename> which in turn take precedence over those
+    in <filename>/usr/lib/</filename>. Drop-in files under any of these directories take precedence
     over unit files wherever located. Multiple drop-in files with different names are applied in
     lexicographic order, regardless of which of the directories they reside in.</para>
 
     start it even manually.</para>
 
     <para>The unit file format is covered by the
-    <ulink
-    url="https://www.freedesktop.org/wiki/Software/systemd/InterfaceStabilityPromise">Interface
-    Stability Promise</ulink>.</para>
+    <ulink url="https://systemd.io/PORTABILITY_AND_STABILITY/">Interface
+    Portability and Stability Promise</ulink>.</para>
 
   </refsect1>
 
     <para>When the input qualifies as absolute file system path, this algorithm is extended slightly: the path to the
     root directory <literal>/</literal> is encoded as single dash <literal>-</literal>. In addition, any leading,
     trailing or duplicate <literal>/</literal> characters are removed from the string before transformation. Example:
-    <filename>/foo//bar/baz/</filename> becomes <literal>foo-bar-baz</literal>.</para>
+    <filename index="false">/foo//bar/baz/</filename> becomes <literal>foo-bar-baz</literal>.</para>
 
     <para>This escaping is fully reversible, as long as it is known whether the escaped string was a path (the
     unescaping results are different for paths and non-path strings). The
             <entry><filename>$XDG_CONFIG_HOME/systemd/user</filename> or <filename>$HOME/.config/systemd/user</filename></entry>
             <entry>User configuration (<varname>$XDG_CONFIG_HOME</varname> is used if set, <filename>~/.config</filename> otherwise)</entry>
           </row>
+          <row>
+            <entry><filename>$XDG_CONFIG_DIRS/systemd/user</filename> or <filename>/etc/xdg/systemd/user</filename></entry>
+            <entry>Additional configuration directories as specified by the XDG base directory specification (<varname>$XDG_CONFIG_DIRS</varname> is used if set, <filename>/etc/xdg</filename> otherwise)</entry>
+          </row>
           <row>
             <entry><filename>/etc/systemd/user</filename></entry>
             <entry>User units created by the administrator</entry>
             <entry><filename>$XDG_DATA_HOME/systemd/user</filename> or <filename>$HOME/.local/share/systemd/user</filename></entry>
             <entry>Units of packages that have been installed in the home directory (<varname>$XDG_DATA_HOME</varname> is used if set, <filename>~/.local/share</filename> otherwise)</entry>
           </row>
+          <row>
+            <entry><filename>$XDG_DATA_DIRS/systemd/user</filename> or <filename>/usr/local/share/systemd/user</filename> and <filename>/usr/share/systemd/user</filename></entry>
+            <entry>Additional data directories as specified by the XDG base directory specification (<varname>$XDG_DATA_DIRS</varname> is used if set, <filename>/usr/local/share</filename> and <filename>/usr/share</filename> otherwise)</entry>
+          </row>
           <row>
             <entry><filename>$dir/systemd/user</filename> for each <varname index="false">$dir</varname> in <varname>$XDG_DATA_DIRS</varname></entry>
             <entry>Additional locations for installed user units, one for each entry in <varname>$XDG_DATA_DIRS</varname></entry>
         <varname>PrivateTmp=</varname> directives (see
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details). If a unit that has this setting set is started, its processes will see the same
-        <filename>/tmp</filename>, <filename>/var/tmp</filename> and network namespace as one listed unit
+        <filename>/tmp/</filename>, <filename>/var/tmp/</filename> and network namespace as one listed unit
         that is started. If multiple listed units are already started, it is not defined which namespace is
-        joined.  Note that this setting only has an effect if
+        joined. Note that this setting only has an effect if
         <varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname> and/or
         <varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
         whose namespace is joined.</para></listitem>
           <literal>vmware</literal>,
           <literal>microsoft</literal>,
           <literal>oracle</literal>,
+          <literal>powervm</literal>,
           <literal>xen</literal>,
           <literal>bochs</literal>,
           <literal>uml</literal>,
           argument must either be a single word, or an assignment (i.e. two words, separated by
           <literal>=</literal>). In the former case the kernel command line is searched for the word
           appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is
-          looked for with right and left hand side matching.</para>
+          looked for with right and left hand side matching. This operates on the kernel command line
+          communicated to userspace via <filename>/proc/cmdline</filename>, except when the service manager
+          is invoked as payload of a container manager, in which case the command line of <filename>PID
+          1</filename> is used instead (i.e. <filename>/proc/1/cmdline</filename>).</para>
           </listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>ConditionNeedsUpdate=</varname></term>
 
-          <listitem><para>Takes one of <filename>/var</filename> or <filename>/etc</filename> as argument,
+          <listitem><para>Takes one of <filename>/var/</filename> or <filename>/etc/</filename> as argument,
           possibly prefixed with a <literal>!</literal> (to invert the condition). This condition may be
           used to conditionalize units on whether the specified directory requires an update because
-          <filename>/usr</filename>'s modification time is newer than the stamp file
+          <filename>/usr/</filename>'s modification time is newer than the stamp file
           <filename>.updated</filename> in the specified directory. This is useful to implement offline
-          updates of the vendor operating system resources in <filename>/usr</filename> that require updating
-          of <filename>/etc</filename> or <filename>/var</filename> on the next following boot. Units making
+          updates of the vendor operating system resources in <filename>/usr/</filename> that require updating
+          of <filename>/etc/</filename> or <filename>/var/</filename> on the next following boot. Units making
           use of this condition should order themselves before
           <citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
           to make sure they run before the stamp file's modification time gets reset indicating a completed
           <term><varname>ConditionFirstBoot=</varname></term>
 
           <listitem><para>Takes a boolean argument. This condition may be used to conditionalize units on
-          whether the system is booting up with an unpopulated <filename>/etc</filename> directory
-          (specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may
-          be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new
-          system instance boots up for the first time.</para>
+          whether the system is booting up for the first time.  This roughly means that <filename>/etc/</filename>
+          is unpopulated (for details, see "First Boot Semantics" in
+          <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+          This may be used to populate <filename>/etc/</filename> on the first boot after factory reset, or
+          when a new system instance boots up for the first time.</para>
+
+          <para>For robustness, units with <varname>ConditionFirstBoot=yes</varname> should order themselves
+          before <filename>first-boot-complete.target</filename> and pull in this passive target with
+          <varname>Wants=</varname>.  This ensures that in a case of an aborted first boot, these units will
+          be re-run during the next system startup.</para>
 
           <para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
           command line (taking a boolean), it will override the result of this condition check, taking
           <row>
             <entry><literal>%E</literal></entry>
             <entry>Configuration directory root</entry>
-            <entry>This is either <filename>/etc</filename> (for the system manager) or the path <literal>$XDG_CONFIG_HOME</literal> resolves to (for user managers).</entry>
+            <entry>This is either <filename>/etc/</filename> (for the system manager) or the path <literal>$XDG_CONFIG_HOME</literal> resolves to (for user managers).</entry>
           </row>
           <row>
             <entry><literal>%f</literal></entry>
@@ -1847,13 +1866,9 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
           <row>
             <entry><literal>%t</literal></entry>
             <entry>Runtime directory root</entry>
-            <entry>This is either <filename>/run</filename> (for the system manager) or the path <literal>$XDG_RUNTIME_DIR</literal> resolves to (for user managers).</entry>
-          </row>
-          <row>
-            <entry><literal>%T</literal></entry>
-            <entry>Directory for temporary files</entry>
-            <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+            <entry>This is either <filename>/run/</filename> (for the system manager) or the path <literal>$XDG_RUNTIME_DIR</literal> resolves to (for user managers).</entry>
           </row>
+          <xi:include href="standard-specifiers.xml" xpointer="T"/>
           <row>
             <entry><literal>%g</literal></entry>
             <entry>User group</entry>
@@ -1879,11 +1894,7 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
 Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry>
           </row>
           <xi:include href="standard-specifiers.xml" xpointer="v"/>
-          <row>
-            <entry><literal>%V</literal></entry>
-            <entry>Directory for larger and persistent temporary files</entry>
-            <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="V"/>
           <xi:include href="standard-specifiers.xml" xpointer="w"/>
           <xi:include href="standard-specifiers.xml" xpointer="W"/>
           <xi:include href="standard-specifiers.xml" xpointer="percent"/>
@@ -1913,7 +1924,7 @@ ExecStart=/usr/sbin/foo-daemon
 
       <para>After running <command>systemctl enable</command>, a
       symlink
-      <filename>/etc/systemd/system/multi-user.target.wants/foo.service</filename>
+      <filename index="false">/etc/systemd/system/multi-user.target.wants/foo.service</filename>
       linking to the actual unit will be created. It tells systemd to
       pull in the unit when starting
       <filename>multi-user.target</filename>. The inverse
index a9040545c2ab6181998ba781912a86c550b5ca6a..20f1a4ebeaf0b0d245bfe7c103af00a060ad906b 100644 (file)
     that need to be executed as part of the boot process. For example,
     it sets the hostname or configures the loopback network device. It
     also sets up and mounts various API file systems, such as
-    <filename>/sys</filename> or <filename>/proc</filename>.</para>
+    <filename>/sys/</filename> or <filename>/proc/</filename>.</para>
 
     <para>For more information about the concepts and
     ideas behind systemd, please refer to the
     <ulink url="http://0pointer.de/blog/projects/systemd.html">Original Design Document</ulink>.</para>
 
-    <para>Note that some but not all interfaces provided
-    by systemd are covered by the
-    <ulink url="https://www.freedesktop.org/wiki/Software/systemd/InterfaceStabilityPromise">Interface
-    Stability Promise</ulink>.</para>
+    <para>Note that some but not all interfaces provided by systemd are covered by the
+    <ulink url="https://systemd.io/PORTABILITY_AND_STABILITY/">Interface Portability and Stability Promise</ulink>.</para>
 
     <para>Units may be generated dynamically at boot and system
     manager reload time, for example based on other configuration
     </para>
 
     <para>Systems which invoke systemd in a container or initrd environment should implement the <ulink
-    url="https://systemd.io/CONTAINER_INTERFACE">Container Interface</ulink> or <ulink
-    url="https://www.freedesktop.org/wiki/Software/systemd/InitrdInterface">initrd Interface</ulink>
+    url="https://systemd.io/CONTAINER_INTERFACE">Container Interface</ulink> or
+    <ulink url="https://systemd.io/INITRD_INTERFACE/">initrd Interface</ulink>
     specifications, respectively.</para>
   </refsect1>
 
     <variablelist class='environment-variables'>
       <varlistentry>
         <term><varname>$SYSTEMD_LOG_COLOR</varname></term>
-        <listitem><para>Controls whether systemd highlights important
-        log messages. This can be overridden with
-        <option>--log-color</option>.</para></listitem>
+        <listitem><para>Controls whether systemd highlights important log messages. This can be overridden
+        with <option>--log-color=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>$SYSTEMD_LOG_LEVEL</varname></term>
-        <listitem><para>systemd reads the log level from this
-        environment variable. This can be overridden with
-        <option>--log-level=</option>.</para></listitem>
+        <listitem><para>systemd reads the log level from this environment variable. This can be overridden
+        with <option>--log-level=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>$SYSTEMD_LOG_LOCATION</varname></term>
-        <listitem><para>Controls whether systemd prints the code
-        location along with log messages. This can be overridden with
-        <option>--log-location</option>.</para></listitem>
+        <listitem><para>Controls whether systemd prints the code location along with log messages. This can
+        be overridden with <option>--log-location=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>$SYSTEMD_LOG_TARGET</varname></term>
-        <listitem><para>systemd reads the log target from this
-        environment variable. This can be overridden with
-        <option>--log-target=</option>.</para></listitem>
+        <listitem><para>systemd reads the log target from this environment variable. This can be overridden
+        with <option>--log-target=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>$SYSTEMD_LOG_TIME</varname></term>
-        <listitem><para>Controls whether systemd prefixes log
-        messages with the current time. This can be overridden with
-        <option>--log-time=</option>.</para></listitem>
+        <listitem><para>Controls whether systemd prefixes log messages with the current time. This can be
+        overridden with <option>--log-time=</option>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SYSTEMD_LOG_TID</varname></term>
+        <listitem><para>Controls whether systemd prefixes log messages with the current thread ID
+        (TID).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <para>These variables may contain a list of paths, separated by colons
         (<literal>:</literal>). When set, if the list ends with an empty
         component (<literal>...:</literal>), this list is prepended to the
-        usual set of of paths. Otherwise, the specified list replaces the usual
+        usual set of paths. Otherwise, the specified list replaces the usual
         set of paths.
         </para></listitem>
       </varlistentry>
       <xi:include href="less-variables.xml" xpointer="pager"/>
       <xi:include href="less-variables.xml" xpointer="less"/>
       <xi:include href="less-variables.xml" xpointer="lesscharset"/>
+      <xi:include href="less-variables.xml" xpointer="lesssecure"/>
       <xi:include href="less-variables.xml" xpointer="colors"/>
       <xi:include href="less-variables.xml" xpointer="urlify"/>
 
         <term><varname>systemd.log_location</varname></term>
         <term><varname>systemd.log_target=</varname></term>
         <term><varname>systemd.log_time</varname></term>
+        <term><varname>systemd.log_tid</varname></term>
 
         <listitem><para>Controls log output, with the same effect as the
-        <varname>$SYSTEMD_LOG_COLOR</varname>,
-        <varname>$SYSTEMD_LOG_LEVEL</varname>,
-        <varname>$SYSTEMD_LOG_LOCATION</varname>,
-        <varname>$SYSTEMD_LOG_TARGET</varname>,
-        <varname>$SYSTEMD_LOG_TIME</varname>, environment variables described above.
-        <varname>systemd.log_color</varname>, <varname>systemd.log_location</varname>, and
-        <varname>systemd.log_time</varname> can be specified without an argument, with the
-        same effect as a positive boolean.</para></listitem>
+        <varname>$SYSTEMD_LOG_COLOR</varname>, <varname>$SYSTEMD_LOG_LEVEL</varname>,
+        <varname>$SYSTEMD_LOG_LOCATION</varname>, <varname>$SYSTEMD_LOG_TARGET</varname>,
+        <varname>$SYSTEMD_LOG_TIME</varname>, and <varname>$SYSTEMD_LOG_TID</varname> environment variables
+        described above. <varname>systemd.log_color</varname>, <varname>systemd.log_location</varname>,
+        <varname>systemd.log_time</varname>, and <varname>systemd.log_tid=</varname> can be specified without
+        an argument, with the same effect as a positive boolean.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       <para>Those options correspond directly to options listed above in "Kernel Command Line". Both forms
       may be used equivalently for the system manager, but it is recommended to use the forms listed above in
       this context, because they are properly namespaced. When an option is specified both on the kernel
-      command line, and as a normal command line argument, the latter has higher precedence.</para>
+      command line and as a normal command line argument, the latter has higher precedence.</para>
 
       <para>When <command>systemd</command> is used as a user manager, the kernel command line is ignored and
-      the options described are understood. Nevertheless, <command>systemd</command> is usually started in
-      this mode through the
+      only the options described below are understood. Nevertheless, <command>systemd</command> is usually
+      started in this mode through the
       <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
       service, which is shared between all users, and it may be more convenient to use configuration files to
-      modify settingssee
-      <citerefentry><refentrytitle>systemd-user.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      or a drop-in that specifies one of the environment variables listed above in the Environment section,
-      see
-      <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+      modify settings (see
+      <citerefentry><refentrytitle>systemd-user.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+      or a drop-in that specifies one of the environment variables listed above in the Environment section
+      (see the discussion of <varname>Environment=</varname> and <varname>EnvironmentFile=</varname> in
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>).</para>
 
       <variablelist>
         <varlistentry>
index 2d5023dc91d4fe1ed79113d08f3c1f08388372e3..52b2d89474af211999533741b76ef5f30562acba 100644 (file)
@@ -260,17 +260,9 @@ r     -        500-900
           <xi:include href="standard-specifiers.xml" xpointer="l"/>
           <xi:include href="standard-specifiers.xml" xpointer="m"/>
           <xi:include href="standard-specifiers.xml" xpointer="o"/>
-          <row>
-            <entry><literal>%T</literal></entry>
-            <entry>Directory for temporary files</entry>
-            <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="T"/>
           <xi:include href="standard-specifiers.xml" xpointer="v"/>
-          <row>
-            <entry><literal>%V</literal></entry>
-            <entry>Directory for larger and persistent temporary files</entry>
-            <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="V"/>
           <xi:include href="standard-specifiers.xml" xpointer="w"/>
           <xi:include href="standard-specifiers.xml" xpointer="W"/>
           <xi:include href="standard-specifiers.xml" xpointer="percent"/>
index b9e9eee96c8a7330f1855238941cb149113257d0..5b81bb5888f4dd3e9a9d574cef373c05a0762c61 100644 (file)
@@ -83,18 +83,18 @@ A+    /path-or-glob/to/append/acls/recursively -    -    -     -           POSIX
     <emphasis>creation</emphasis> of regular files, directories, pipes, and device nodes, adjustments to
     their <emphasis>access mode, ownership, attributes, quota assignments, and contents</emphasis>, and
     finally their time-based <emphasis>removal</emphasis>. It is mostly commonly used for volatile and
-    temporary files and directories (such as those located under <filename>/run</filename>,
-    <filename>/tmp</filename>, <filename>/var/tmp</filename>, the API file systems such as
-    <filename>/sys</filename> or <filename>/proc</filename>, as well as some other directories below
-    <filename>/var</filename>).</para>
+    temporary files and directories (such as those located under <filename>/run/</filename>,
+    <filename>/tmp/</filename>, <filename>/var/tmp/</filename>, the API file systems such as
+    <filename>/sys/</filename> or <filename>/proc/</filename>, as well as some other directories below
+    <filename>/var/</filename>).</para>
 
     <para><command>systemd-tmpfiles</command> uses this configuration to create volatile files and
     directories during boot and to do periodic cleanup afterwards. See
     <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
     the description of <filename>systemd-tmpfiles-setup.service</filename>,
-    <filename>systemd-tmpfiles-cleanup.service</filename>, and associated units.</para>
+    <filename>systemd-tmpfiles-clean.service</filename>, and associated units.</para>
 
-    <para>System daemons frequently require private runtime directories below <filename>/run</filename> to
+    <para>System daemons frequently require private runtime directories below <filename>/run/</filename> to
     store communication sockets and similar. For these, it is better to use
     <varname>RuntimeDirectory=</varname> in their unit files (see
     <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
@@ -258,11 +258,11 @@ L     /tmp/foobar -    -    -     -   /dev/null</programlisting>
 
           <para>It is recommended to use <varname>Q</varname> for subvolumes that typically contain further subvolumes,
           and where it is desirable to have accounting and quota limits on all child subvolumes together. Examples for
-          <varname>Q</varname> are typically <filename>/home</filename> or <filename>/var/lib/machines</filename>. In
+          <varname>Q</varname> are typically <filename>/home/</filename> or <filename>/var/lib/machines/</filename>. In
           contrast, <varname>q</varname> should be used for subvolumes that either usually do not include further
           subvolumes or where no accounting and quota limits are needed that apply to all child subvolumes
-          together. Examples for <varname>q</varname> are typically <filename>/var</filename> or
-          <filename>/var/tmp</filename>. </para>
+          together. Examples for <varname>q</varname> are typically <filename>/var/</filename> or
+          <filename>/var/tmp/</filename>. </para>
 
           <para>As with <varname>q</varname>, <varname>Q</varname> has no effect on the quota group hierarchy if the
           subvolume already exists, regardless of whether the subvolume already belong to a quota group or not.
@@ -661,13 +661,9 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
             <row>
               <entry><literal>%t</literal></entry>
               <entry>System or user runtime directory</entry>
-              <entry>In <option>--user</option> mode, this is the same <varname>$XDG_RUNTIME_DIR</varname>, and <filename>/run</filename> otherwise.</entry>
-            </row>
-            <row>
-              <entry><literal>%T</literal></entry>
-              <entry>Directory for temporary files</entry>
-              <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+              <entry>In <option>--user</option> mode, this is the same <varname>$XDG_RUNTIME_DIR</varname>, and <filename>/run/</filename> otherwise.</entry>
             </row>
+            <xi:include href="standard-specifiers.xml" xpointer="T"/>
             <row>
               <entry><literal>%g</literal></entry>
               <entry>User group</entry>
@@ -689,11 +685,7 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
               <entry>This is the numeric UID of the user running the command. In case of the system instance this resolves to <constant>0</constant>.</entry>
             </row>
             <xi:include href="standard-specifiers.xml" xpointer="v"/>
-            <row>
-              <entry><literal>%V</literal></entry>
-              <entry>Directory for larger and persistent temporary files</entry>
-              <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="V"/>
             <xi:include href="standard-specifiers.xml" xpointer="w"/>
             <xi:include href="standard-specifiers.xml" xpointer="W"/>
             <xi:include href="standard-specifiers.xml" xpointer="percent"/>
index 0b5669b4425b8dfcbc0e14c0a320c351151ef058..aa695b5e04b8587bd9a3d0281c9e335375e5b045 100644 (file)
@@ -88,7 +88,7 @@
         <term><varname>resolve_names=</varname></term>
 
         <listitem>
-          <para>Specifes when systemd-udevd should resolve names of users and groups.  When set to
+          <para>Specifies when systemd-udevd should resolve names of users and groups.  When set to
           <option>early</option> (the default), names will be resolved when the rules are parsed.
           When set to <option>late</option>, names will be resolved for every event.  When set to
           <option>never</option>, names will never be resolved and all devices will be owned by
index 350ebcf5a2db5ef94869f940bc20c1b4114d397d..a41a39a43f9726ce7697f7eeda0a4d6903a98bb9 100644 (file)
@@ -25,7 +25,7 @@
 
   <refsect1><title>Description</title>
     <para>udev supplies the system software with device events, manages permissions
-    of device nodes and may create additional symlinks in the <filename>/dev</filename>
+    of device nodes and may create additional symlinks in the <filename>/dev/</filename>
     directory, or renames network interfaces. The kernel usually just assigns unpredictable
     device names based on the order of discovery. Meaningful symlinks or network device
     names provide a way to reliably identify devices based on their properties or
       volatile runtime directory <filename>/run/udev/rules.d</filename> and the local administration
       directory <filename>/etc/udev/rules.d</filename>.  All rules files are collectively sorted and
       processed in lexical order, regardless of the directories in which they live. However, files with
-      identical filenames replace each other. Files in <filename>/etc</filename> have the highest priority,
-      files in <filename>/run</filename> take precedence over files with the same name under
-      <filename>/usr</filename>. This can be used to override a system-supplied rules file with a local
-      file if needed; a symlink in <filename>/etc</filename> with the same name as a rules file in
-      <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>, disables the rules file
+      identical filenames replace each other. Files in <filename>/etc/</filename> have the highest priority,
+      files in <filename>/run/</filename> take precedence over files with the same name under
+      <filename>/usr/</filename>. This can be used to override a system-supplied rules file with a local
+      file if needed; a symlink in <filename>/etc/</filename> with the same name as a rules file in
+      <filename>/usr/lib/</filename>, pointing to <filename>/dev/null</filename>, disables the rules file
       entirely. Rule files must have the extension <filename>.rules</filename>; other extensions are
       ignored.</para>
 
index 118adfa2c7ffa303711e78910f374b68d7c7dc29..763041d223e43b4f5c75b6fc0c98ce1507a544b2 100644 (file)
     <function>udev_device_new_from_subsystem_sysname</function>, and
     <function>udev_device_new_from_device_id</function>
     create the device object based on information found in
-    <filename>/sys</filename>, annotated with properties from the udev-internal
-    device database. A syspath is any subdirectory of <filename>/sys</filename>,
+    <filename>/sys/</filename>, annotated with properties from the udev-internal
+    device database. A syspath is any subdirectory of <filename>/sys/</filename>,
     with the restriction that a subdirectory of <filename>/sys/devices</filename>
     (or a symlink to one) represents a real device and as such must contain
     a <filename>uevent</filename> file. <function>udev_device_new_from_devnum</function>
index c78faa5a0660dc920fff32a7b50d5fceb55c1205..d2f6083bae0f6b8ffc16a05ae4a7a0ee1dcf7b9f 100644 (file)
           <term><option>-p</option></term>
           <term><option>--path=<replaceable>DEVPATH</replaceable></option></term>
           <listitem>
-            <para>The <filename>/sys</filename> path of the device to query, e.g.
-            <filename><optional>/sys</optional>/class/block/sda</filename>. This option is an alternative to
+            <para>The <filename>/sys/</filename> path of the device to query, e.g.
+            <filename><optional>/sys/</optional>/class/block/sda</filename>. This option is an alternative to
             the positional argument with a <filename>/sys/</filename> prefix. <command>udevadm info
             --path=/class/block/sda</command> is equivalent to <command>udevadm info
             /sys/class/block/sda</command>.</para>
           <term><option>--name=<replaceable>FILE</replaceable></option></term>
           <listitem>
             <para>The name of the device node or a symlink to query,
-            e.g. <filename><optional>/dev</optional>/sda</filename>. This option is an alternative to the
+            e.g. <filename><optional>/dev/</optional>/sda</filename>. This option is an alternative to the
             positional argument with a <filename>/dev/</filename> prefix. <command>udevadm info
             --name=sda</command> is equivalent to <command>udevadm info /dev/sda</command>.</para>
           </listitem>
           <term><option>--sysname-match=<replaceable>NAME</replaceable></option></term>
           <listitem>
             <para>Trigger events for devices for which the last component (i.e. the filename) of the
-            <filename>/sys</filename> path matches the specified <replaceable>PATH</replaceable>. This option
+            <filename>/sys/</filename> path matches the specified <replaceable>PATH</replaceable>. This option
             supports shell style pattern matching. When this option is specified more than once, then each
             matching result is ORed, that is, all devices which have any of the specified
             <replaceable>NAME</replaceable> are triggered.</para>
 
       <para>In addition, optional positional arguments can be used
       to specify device names or sys paths. They must start with
-      <filename>/dev</filename> or <filename>/sys</filename>
+      <filename>/dev/</filename> or <filename>/sys/</filename>
       respectively.</para>
     </refsect2>
 
index d719160a1f4cc4719f0efcedfdfc0ca57313b7bd..307d1bd5f7c30461cd51585305ae79d2af28d584 100644 (file)
@@ -38,8 +38,8 @@ relative_source_path = run_command('realpath',
                                    project_source_root).stdout().strip()
 conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path)
 
-conf.set10('DEVELOPER_MODE', get_option('mode') == 'developer',
-           description : 'enable additional checks only suitable in development')
+conf.set('BUILD_MODE', 'BUILD_MODE_' + get_option('mode').to_upper(),
+         description : 'tailor build to development or release builds')
 
 want_ossfuzz = get_option('oss-fuzz')
 want_libfuzzer = get_option('llvm-fuzz')
@@ -299,6 +299,7 @@ substs.set('CERTIFICATEROOT',                                 get_option('certif
 substs.set('RANDOM_SEED',                                     join_paths(randomseeddir, 'random-seed'))
 substs.set('SYSTEM_SYSVINIT_PATH',                            sysvinit_path)
 substs.set('SYSTEM_SYSVRCND_PATH',                            sysvrcnd_path)
+substs.set('SYSTEMD_TEST_DATA',                               join_paths(testsdir, 'testdata'))
 substs.set('RC_LOCAL_PATH',                                   get_option('rc-local'))
 substs.set('MEMORY_ACCOUNTING_DEFAULT',                       memory_accounting_default ? 'yes' : 'no')
 substs.set('STATUS_UNIT_FORMAT_DEFAULT',                      status_unit_format_default)
@@ -531,6 +532,8 @@ foreach ident : [
                                  #include <unistd.h>
                                  #include <signal.h>
                                  #include <sys/wait.h>'''],
+        ['mallinfo',          '''#include <malloc.h>'''],
+        ['close_range',       '''#include <unistd.h>'''],
 ]
 
         have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
@@ -694,35 +697,31 @@ if time_epoch == -1
 endif
 conf.set('TIME_EPOCH', time_epoch)
 
-system_uid_max = get_option('system-uid-max')
-if system_uid_max == -1
-        system_uid_max = run_command(
-                awk,
-                '/^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }',
-                '/etc/login.defs').stdout().strip()
-        if system_uid_max == ''
-                system_uid_max = 999
-        else
-                system_uid_max = system_uid_max.to_int()
+foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1],  # Also see login.defs(5).
+                 ['system-uid-max',       'SYS_UID_MAX', 999],
+                 ['system-alloc-gid-min', 'SYS_GID_MIN', 1],
+                 ['system-gid-max',       'SYS_GID_MAX', 999]]
+        v = get_option(tuple[0])
+        if v == -1
+                v = run_command(
+                        awk,
+                        '/^\s*@0@\s+/ { uid=$2 } END { print uid }'.format(tuple[1]),
+                        '/etc/login.defs').stdout().strip()
+                if v == ''
+                        v = tuple[2]
+                else
+                        v = v.to_int()
+                endif
         endif
+        conf.set(tuple[0].underscorify().to_upper(), v)
+        substs.set(tuple[0].underscorify().to_upper(), v)
+endforeach
+if conf.get('SYSTEM_ALLOC_UID_MIN') >= conf.get('SYSTEM_UID_MAX')
+        error('Invalid uid allocation range')
 endif
-conf.set('SYSTEM_UID_MAX', system_uid_max)
-substs.set('systemuidmax', system_uid_max)
-
-system_gid_max = get_option('system-gid-max')
-if system_gid_max == -1
-        system_gid_max = run_command(
-                awk,
-                '/^\s*SYS_GID_MAX\s+/ { gid=$2 } END { print gid }',
-                '/etc/login.defs').stdout().strip()
-        if system_gid_max == ''
-                system_gid_max = 999
-        else
-                system_gid_max = system_gid_max.to_int()
-        endif
+if conf.get('SYSTEM_ALLOC_GID_MIN') >= conf.get('SYSTEM_GID_MAX')
+        error('Invalid gid allocation range')
 endif
-conf.set('SYSTEM_GID_MAX', system_gid_max)
-substs.set('systemgidmax', system_gid_max)
 
 dynamic_uid_min = get_option('dynamic-uid-min')
 dynamic_uid_max = get_option('dynamic-uid-max')
@@ -1413,6 +1412,17 @@ conf.set10('ENABLE_HOMED', have)
 have = have and conf.get('HAVE_PAM') == 1
 conf.set10('ENABLE_PAM_HOME', have)
 
+have = get_option('oomd')
+if have == 'auto'
+        have = get_option('mode') == 'developer'
+else
+        have = have == 'true'
+        if have and get_option('mode') != 'developer'
+                error('oomd is not available in release mode (yet)')
+        endif
+endif
+conf.set10('ENABLE_OOMD', have)
+
 want_remote = get_option('remote')
 if want_remote != 'false'
         have_deps = [conf.get('HAVE_MICROHTTPD') == 1,
@@ -1444,6 +1454,7 @@ foreach term : ['analyze',
                 'idn',
                 'ima',
                 'initrd',
+                'compat-mutable-uid-boundaries',
                 'ldconfig',
                 'localed',
                 'logind',
@@ -1451,6 +1462,7 @@ foreach term : ['analyze',
                 'networkd',
                 'nss-myhostname',
                 'nss-systemd',
+                'oomd',
                 'portabled',
                 'pstore',
                 'quotacheck',
@@ -1470,8 +1482,11 @@ foreach term : ['analyze',
         have = get_option(term)
         name = 'ENABLE_' + term.underscorify().to_upper()
         conf.set10(name, have)
+        substs.set10(name, have)
 endforeach
 
+enable_sysusers = conf.get('ENABLE_SYSUSERS') == 1
+
 foreach tuple : [['nss-mymachines', 'machined'],
                  ['nss-resolve',    'resolve']]
         want = get_option(tuple[0])
@@ -1668,6 +1683,7 @@ subdir('src/analyze')
 subdir('src/journal-remote')
 subdir('src/coredump')
 subdir('src/pstore')
+subdir('src/oom')
 subdir('src/hostname')
 subdir('src/import')
 subdir('src/partition')
@@ -2104,9 +2120,77 @@ endif
 
 public_programs += executable(
         'systemctl',
+        'src/systemctl/systemctl-add-dependency.c',
+        'src/systemctl/systemctl-add-dependency.h',
+        'src/systemctl/systemctl-cancel-job.c',
+        'src/systemctl/systemctl-cancel-job.h',
+        'src/systemctl/systemctl-clean-or-freeze.c',
+        'src/systemctl/systemctl-clean-or-freeze.h',
+        'src/systemctl/systemctl-compat-halt.c',
+        'src/systemctl/systemctl-compat-halt.h',
+        'src/systemctl/systemctl-compat-runlevel.c',
+        'src/systemctl/systemctl-compat-runlevel.h',
+        'src/systemctl/systemctl-compat-shutdown.c',
+        'src/systemctl/systemctl-compat-shutdown.h',
+        'src/systemctl/systemctl-compat-telinit.c',
+        'src/systemctl/systemctl-compat-telinit.h',
+        'src/systemctl/systemctl-daemon-reload.c',
+        'src/systemctl/systemctl-daemon-reload.h',
+        'src/systemctl/systemctl-edit.c',
+        'src/systemctl/systemctl-edit.h',
+        'src/systemctl/systemctl-enable.c',
+        'src/systemctl/systemctl-enable.h',
+        'src/systemctl/systemctl-is-active.c',
+        'src/systemctl/systemctl-is-active.h',
+        'src/systemctl/systemctl-is-enabled.c',
+        'src/systemctl/systemctl-is-enabled.h',
+        'src/systemctl/systemctl-is-system-running.c',
+        'src/systemctl/systemctl-is-system-running.h',
+        'src/systemctl/systemctl-kill.c',
+        'src/systemctl/systemctl-kill.h',
+        'src/systemctl/systemctl-list-dependencies.c',
+        'src/systemctl/systemctl-list-dependencies.h',
+        'src/systemctl/systemctl-list-jobs.c',
+        'src/systemctl/systemctl-list-jobs.h',
+        'src/systemctl/systemctl-list-machines.c',
+        'src/systemctl/systemctl-list-machines.h',
+        'src/systemctl/systemctl-list-unit-files.c',
+        'src/systemctl/systemctl-list-unit-files.h',
+        'src/systemctl/systemctl-list-units.c',
+        'src/systemctl/systemctl-list-units.h',
+        'src/systemctl/systemctl-log-setting.c',
+        'src/systemctl/systemctl-log-setting.h',
+        'src/systemctl/systemctl-logind.c',
+        'src/systemctl/systemctl-logind.h',
+        'src/systemctl/systemctl-preset-all.c',
+        'src/systemctl/systemctl-preset-all.h',
+        'src/systemctl/systemctl-reset-failed.c',
+        'src/systemctl/systemctl-reset-failed.h',
+        'src/systemctl/systemctl-service-watchdogs.c',
+        'src/systemctl/systemctl-service-watchdogs.h',
+        'src/systemctl/systemctl-set-default.c',
+        'src/systemctl/systemctl-set-default.h',
+        'src/systemctl/systemctl-set-environment.c',
+        'src/systemctl/systemctl-set-environment.h',
+        'src/systemctl/systemctl-set-property.c',
+        'src/systemctl/systemctl-set-property.h',
+        'src/systemctl/systemctl-show.c',
+        'src/systemctl/systemctl-show.h',
+        'src/systemctl/systemctl-start-special.c',
+        'src/systemctl/systemctl-start-special.h',
+        'src/systemctl/systemctl-start-unit.c',
+        'src/systemctl/systemctl-start-unit.h',
+        'src/systemctl/systemctl-switch-root.c',
+        'src/systemctl/systemctl-switch-root.h',
+        'src/systemctl/systemctl-sysv-compat.c',
+        'src/systemctl/systemctl-sysv-compat.h',
+        'src/systemctl/systemctl-trivial-method.c',
+        'src/systemctl/systemctl-trivial-method.h',
+        'src/systemctl/systemctl-util.c',
+        'src/systemctl/systemctl-util.c',
+        'src/systemctl/systemctl-util.h',
         'src/systemctl/systemctl.c',
-        'src/systemctl/sysv-compat.h',
-        'src/systemctl/sysv-compat.c',
+        'src/systemctl/systemctl.h',
         include_directories : includes,
         link_with : systemctl_link_with,
         dependencies : [threads,
@@ -2659,6 +2743,27 @@ if conf.get('ENABLE_PSTORE') == 1
                 install_dir : rootlibexecdir)
 endif
 
+if conf.get('ENABLE_OOMD') == 1
+        executable('systemd-oomd',
+                   systemd_oomd_sources,
+                   include_directories : includes,
+                   link_with : [libshared],
+                   dependencies : [],
+                   install_rpath : rootlibexecdir,
+                   install : true,
+                   install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                   'oomctl',
+                   oomctl_sources,
+                   include_directories : includes,
+                   link_with : [libshared],
+                   dependencies : [],
+                   install_rpath : rootlibexecdir,
+                   install : true,
+                   install_dir : rootbindir)
+endif
+
 if conf.get('ENABLE_BINFMT') == 1
         public_programs += executable(
                 'systemd-binfmt',
@@ -2966,8 +3071,8 @@ public_programs += executable(
         install_rpath : rootlibexecdir,
         install : true)
 
-if conf.get('ENABLE_SYSUSERS') == 1
-        public_programs += executable(
+if enable_sysusers
+        exe = executable(
                 'systemd-sysusers',
                 'src/sysusers/sysusers.c',
                 include_directories : includes,
@@ -2975,12 +3080,21 @@ if conf.get('ENABLE_SYSUSERS') == 1
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootbindir)
+        public_programs += exe
+
+        if want_tests != 'false'
+                test('test-sysusers',
+                     test_sysusers_sh,
+                     # https://github.com/mesonbuild/meson/issues/2681
+                     args : exe.full_path())
+        endif
 
         if have_standalone_binaries
-                public_programs += executable(
+                exe = executable(
                         'systemd-sysusers.standalone',
                         'src/sysusers/sysusers.c',
                         include_directories : includes,
+                        c_args : '-DSTANDALONE',
                         link_with : [libshared_static,
                                      libbasic,
                                      libbasic_gcrypt,
@@ -2988,6 +3102,14 @@ if conf.get('ENABLE_SYSUSERS') == 1
                                      libjournal_client],
                         install : true,
                         install_dir : rootbindir)
+                public_programs += exe
+
+                if want_tests != 'false'
+                        test('test-sysusers.standalone',
+                             test_sysusers_sh,
+                             # https://github.com/mesonbuild/meson/issues/2681
+                             args : exe.full_path())
+                endif
         endif
 endif
 
@@ -3015,6 +3137,7 @@ if conf.get('ENABLE_TMPFILES') == 1
                         'systemd-tmpfiles.standalone',
                         systemd_tmpfiles_sources,
                         include_directories : includes,
+                        c_args : '-DSTANDALONE',
                         link_with : [libshared_static,
                                      libbasic,
                                      libbasic_gcrypt,
@@ -3539,12 +3662,12 @@ status = [
                                                               get_option('debug-tty')),
         'TTY GID:                           @0@'.format(tty_gid),
         'users GID:                         @0@'.format(substs.get('USERS_GID')),
-        'maximum system UID:                @0@'.format(system_uid_max),
-        'maximum system GID:                @0@'.format(system_gid_max),
-        'minimum dynamic UID:               @0@'.format(dynamic_uid_min),
-        'maximum dynamic UID:               @0@'.format(dynamic_uid_max),
-        'minimum container UID base:        @0@'.format(container_uid_base_min),
-        'maximum container UID base:        @0@'.format(container_uid_base_max),
+        'system UIDs:                       <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
+                                                                        conf.get('SYSTEM_ALLOC_UID_MIN')),
+        'system GIDs:                       <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
+                                                                        conf.get('SYSTEM_ALLOC_GID_MIN')),
+        'dynamic UIDs:                      @0@–@1@'.format(dynamic_uid_min, dynamic_uid_max),
+        'container UID bases:               @0@–@1@'.format(container_uid_base_min, container_uid_base_max),
         '/dev/kvm access mode:              @0@'.format(get_option('dev-kvm-mode')),
         'render group access mode:          @0@'.format(get_option('group-render-mode')),
         'certificate root directory:        @0@'.format(get_option('certificate-root')),
@@ -3628,6 +3751,7 @@ foreach tuple : [
         ['libcurl'],
         ['idn'],
         ['initrd'],
+        ['compat-mutable-uid-boundaries'],
         ['libidn2'],
         ['libidn'],
         ['libiptc'],
@@ -3660,6 +3784,7 @@ foreach tuple : [
         ['DNS-over-TLS(openssl)', conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1],
         ['coredump'],
         ['pstore'],
+        ['oomd'],
         ['polkit'],
         ['legacy pkla',      install_polkit_pkla],
         ['efi'],
index fc9e4379f38f92e5e544cee1219453f730a07af6..2c10054769fcea2e2fe1b2b97be119e4d4fc07d0 100644 (file)
@@ -5,7 +5,7 @@ option('version-tag', type : 'string',
        description : 'override the git version string')
 
 option('mode', type : 'combo', choices : ['developer', 'release'],
-       description : 'enable additional checks suitable for systemd development')
+       description : 'autoenable features suitable for systemd development/release builds')
 
 option('split-usr', type : 'combo', choices : ['auto', 'true', 'false'],
        description : '''/bin, /sbin aren't symlinks into /usr''')
@@ -28,9 +28,9 @@ option('static-libsystemd', type : 'combo',
        description : '''install a static library for libsystemd''')
 option('static-libudev', type : 'combo',
        choices : ['false', 'true', 'pic', 'no-pic'],
-       description : '''install a static library for libudev''')
+       description : 'install a static library for libudev')
 option('standalone-binaries', type : 'boolean', value : 'false',
-       description : '''also build standalone versions of supported binaries''')
+       description : 'also build standalone versions of supported binaries')
 
 option('sysvinit-path', type : 'string', value : '/etc/init.d',
        description : 'the directory where the SysV init scripts are located')
@@ -40,8 +40,10 @@ option('telinit-path', type : 'string', value : '/lib/sysvinit/telinit',
        description : 'path to telinit')
 option('rc-local', type : 'string',
        value : '/etc/rc.local')
-option('initrd', type: 'boolean',
+option('initrd', type : 'boolean',
        description : 'install services for use when running systemd in initrd')
+option('compat-mutable-uid-boundaries', type : 'boolean', value : 'false',
+       description : 'look at uid boundaries in /etc/login.defs for compatibility')
 
 option('quotaon-path', type : 'string', description : 'path to quotaon')
 option('quotacheck-path', type : 'string', description : 'path to quotacheck')
@@ -95,6 +97,8 @@ option('coredump', type : 'boolean',
        description : 'install the coredump handler')
 option('pstore', type : 'boolean',
        description : 'install the pstore archival tool')
+option('oomd', type : 'combo', choices : ['auto', 'true', 'false'],
+       description : 'install the userspace oom killer')
 option('logind', type : 'boolean',
        description : 'install the systemd-logind stack')
 option('hostnamed', type : 'boolean',
@@ -192,6 +196,10 @@ option('status-unit-format-default', type : 'combo',
        description : 'use unit name or description in messages by default')
 option('time-epoch', type : 'integer', value : '-1',
        description : 'time epoch for time clients')
+option('system-alloc-uid-min', type : 'integer', value : '-1',
+       description : 'minimum system UID used when allocating')
+option('system-alloc-gid-min', type : 'integer', value : '-1',
+       description : 'minimum system GID used when allocating')
 option('system-uid-max', type : 'integer', value : '-1',
        description : 'maximum system UID')
 option('system-gid-max', type : 'integer', value : '-1',
index 3286e1ab69b714d5674481ba872e0b6ac4cd6f32..b7e667435168f99b15c25ee72c68d824e515e565 100644 (file)
--- a/po/be.po
+++ b/po/be.po
@@ -4,21 +4,23 @@
 #
 #
 # Viktar Vaŭčkievič <victorenator@gmail.com>, 2015, 2016.
+# Zmicer Turok <nashtlumach@gmail.com>, 2020.
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd master\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-08-19 18:02+0200\n"
-"PO-Revision-Date: 2016-06-09 19:47+0300\n"
-"Last-Translator: Viktar Vaŭčkievič <victorenator@gmail.com>\n"
-"Language-Team: \n"
+"PO-Revision-Date: 2020-10-16 06:30+0000\n"
+"Last-Translator: Zmicer Turok <nashtlumach@gmail.com>\n"
+"Language-Team: Belarusian <https://translate.fedoraproject.org/projects/"
+"systemd/master/be/>\n"
 "Language: be\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%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-"X-Generator: Lokalize 2.0\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.2.2\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -27,39 +29,39 @@ msgstr "Адправіць пароль назад сістэме"
 #: src/core/org.freedesktop.systemd1.policy.in:23
 msgid ""
 "Authentication is required to send the entered passphrase back to the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð°Ð´Ð¿Ñ\80аÑ\9eкÑ\96 Ð¿Ð°Ñ\80олÑ\8f Ð½Ð°Ð·Ð°Ð´ Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме."
+msgstr "Ð\9aаб Ð°Ð´Ð¿Ñ\80авÑ\96Ñ\86Ñ\8c Ð¿Ð°Ñ\80олÑ\8c Ð½Ð°Ð·Ð°Ð´ Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме, Ð¿Ð°Ñ\82Ñ\80бÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/org.freedesktop.systemd1.policy.in:33
 msgid "Manage system services or other units"
-msgstr "Кіраваць сэрвісамі і іншымі сістэмнымі адзінкамі"
+msgstr "Кіраванне сістэмнымі службамі і іншымі адзінкамі"
 
 #: src/core/org.freedesktop.systemd1.policy.in:34
 msgid "Authentication is required to manage system services or other units."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ñ\81Ñ\8dÑ\80вÑ\96Ñ\81амÑ\96 Ñ\96 Ñ\96нÑ\88Ñ\8bмÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bмÑ\96 "
-"адзінкамі."
+"Ð\94лÑ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bмÑ\96 Ñ\81лÑ\83жбамÑ\96 Ñ\96 Ñ\96нÑ\88Ñ\8bмÑ\96 Ð°Ð´Ð·Ñ\96нкамÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аўтэнтыфікацыя."
 
 #: src/core/org.freedesktop.systemd1.policy.in:43
 msgid "Manage system service or unit files"
-msgstr "Кіраваць файламі сэрвісаў і іншых сістэмных адзінак"
+msgstr "Кіраванне файламі сістэмных службаў і іншых адзінак"
 
 #: src/core/org.freedesktop.systemd1.policy.in:44
 msgid "Authentication is required to manage system service or unit files."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ñ\84айламÑ\96 Ñ\81Ñ\8dÑ\80вÑ\96Ñ\81аÑ\9e Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bÑ\85 "
-"адзінак."
+"Ð\94лÑ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ñ\84айламÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bÑ\85 Ñ\81лÑ\83жбаÑ\9e Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 Ð°Ð´Ð·Ñ\96нак Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аўтэнтыфікацыя."
 
 #: src/core/org.freedesktop.systemd1.policy.in:54
 msgid "Set or unset system and service manager environment variables"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ð°Ð±Ð¾ Ñ\81кÑ\96нÑ\83Ñ\86Ñ\8c Ð·Ð¼ÐµÐ½Ð½Ñ\8bÑ\8f Ð°Ñ\81Ñ\8fÑ\80оддзÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ð¼Ñ\8dнÑ\8dджÑ\8dÑ\80а"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ð·Ð¼ÐµÐ½Ð½Ñ\8bÑ\8f Ð°Ñ\81Ñ\8fÑ\80оддзÑ\8f ÐºÑ\96Ñ\80аÑ\9eнÑ\96ка Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b"
 
 #: src/core/org.freedesktop.systemd1.policy.in:55
 msgid ""
 "Authentication is required to set or unset system and service manager "
 "environment variables."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ð°Ð±Ð¾ Ñ\81кÑ\96дÑ\83 Ð·Ð¼ÐµÐ½Ð½Ñ\8bÑ\85 Ð°Ñ\81Ñ\8fÑ\80оддзÑ\8f "
-"сістэмнага мэнэджэра."
+"Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ð·Ð¼ÐµÐ½Ð½Ñ\8bÑ\85 Ð°Ñ\81Ñ\8fÑ\80оддзÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага ÐºÑ\96Ñ\80аÑ\9eнÑ\96ка Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аўтэнтыфікацыя."
 
 #: src/core/org.freedesktop.systemd1.policy.in:64
 msgid "Reload the systemd state"
@@ -67,154 +69,139 @@ msgstr "Перачытаць стан systemd"
 
 #: src/core/org.freedesktop.systemd1.policy.in:65
 msgid "Authentication is required to reload the systemd state."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 systemd."
+msgstr "Ð\9aаб Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аÑ\86Ñ\8c Ñ\81Ñ\82ан systemd, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/home/org.freedesktop.home1.policy:13
 msgid "Create a home area"
-msgstr ""
+msgstr "Стварыць хатнюю прастору"
 
 #: src/home/org.freedesktop.home1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to create a user's home area."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 systemd."
+msgstr "Ð\94лÑ\8f Ñ\81Ñ\82ваÑ\80Ñ\8dннÑ\8f Ñ\85аÑ\82нÑ\8fй Ð¿Ñ\80аÑ\81Ñ\82оÑ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/home/org.freedesktop.home1.policy:23
 msgid "Remove a home area"
-msgstr ""
+msgstr "Выдаліць хатнюю прастору"
 
 #: src/home/org.freedesktop.home1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to remove a user's home area."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 systemd."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bдаленнÑ\8f Ñ\85аÑ\82нÑ\8fй Ð¿Ñ\80аÑ\81Ñ\82оÑ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/home/org.freedesktop.home1.policy:33
 msgid "Check credentials of a home area"
-msgstr ""
+msgstr "Праверыць уліковыя даныя хатняй прасторы"
 
 #: src/home/org.freedesktop.home1.policy:34
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
 msgid ""
 "Authentication is required to check credentials against a user's home area."
-msgstr ""
-"Неабходна аўтэнтыфікацыя для кіравання актыўнымі сесіямі, карыстальнікамі і "
-"месцамі."
+msgstr "Для праверкі ўліковых даных хатняй прасторы патрабуецца аўтэнтыфікацыя."
 
 #: src/home/org.freedesktop.home1.policy:43
 msgid "Update a home area"
-msgstr ""
+msgstr "Абнавіць хатнюю прастору"
 
 #: src/home/org.freedesktop.home1.policy:44
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
 msgid "Authentication is required to update a user's home area."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð»Ñ\83Ñ\87Ñ\8dннÑ\8f Ð¿Ñ\80Ñ\8bлад Ð´Ð° Ð¿Ñ\80аÑ\86оÑ\9eнÑ\8bÑ\85 Ð¼ÐµÑ\81Ñ\86аÑ\9e."
+msgstr "Ð\94лÑ\8f Ð°Ð±Ð½Ð°Ñ\9eленнÑ\8f Ñ\85аÑ\82нÑ\8fй Ð¿Ñ\80аÑ\81Ñ\82оÑ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/home/org.freedesktop.home1.policy:53
 msgid "Resize a home area"
-msgstr ""
+msgstr "Змяніць памер хатняй прасторы"
 
 #: src/home/org.freedesktop.home1.policy:54
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to resize a user's home area."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½Ñ\8f"
+msgstr "Ð\94лÑ\8f Ð·Ð¼ÐµÐ½Ñ\8b Ð¿Ð°Ð¼ÐµÑ\80Ñ\83 Ñ\85аÑ\82нÑ\8fй Ð¿Ñ\80аÑ\81Ñ\82оÑ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/home/org.freedesktop.home1.policy:63
 msgid "Change password of a home area"
-msgstr ""
+msgstr "Змяніць пароль для хатняй прасторы"
 
 #: src/home/org.freedesktop.home1.policy:64
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
 msgid ""
 "Authentication is required to change the password of a user's home area."
-msgstr ""
-"Неабходна аўтэнтыфікацыя для кіравання актыўнымі сесіямі, карыстальнікамі і "
-"месцамі."
+msgstr "Для змены пароля для хатняй прасторы патрабуецца аўтэнтыфікацыя."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
 msgid "Set hostname"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\96мÑ\8f Ð²Ñ\83зла"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ð½Ð°Ð·Ð²Ñ\83 ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80а"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
 msgid "Authentication is required to set the local hostname."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\96мÑ\8f Ð²Ñ\83зла."
+msgstr "Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ð½Ð°Ð·Ð²Ñ\8b ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80а Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
 msgid "Set static hostname"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\81Ñ\82аÑ\82Ñ\8bÑ\87нае Ñ\96мÑ\8f Ð²Ñ\83зла"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ñ\81Ñ\82аÑ\82Ñ\8bÑ\87нÑ\83Ñ\8e Ð½Ð°Ð·Ð²Ñ\83 ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80а"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
 "Authentication is required to set the statically configured local hostname, "
 "as well as the pretty hostname."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\8fк Ñ\81Ñ\82аÑ\82Ñ\8bÑ\87нага Ñ\82ак Ñ\96 Ð¿Ñ\80Ñ\8bгожага Ñ\96мÑ\8f "
-"вÑ\83зла."
+"Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ñ\8fк Ñ\81Ñ\82аÑ\82Ñ\8bÑ\87най, Ñ\82ак Ñ\96 Ð·Ñ\80азÑ\83мелай, Ð½Ð°Ð·Ð²Ñ\8b ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80а Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/hostname/org.freedesktop.hostname1.policy:41
 msgid "Set machine information"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\96нÑ\84аÑ\80маÑ\86Ñ\8bÑ\8e Ð°Ð± Ð¼Ð°Ñ\88Ñ\8bне"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ð·Ð²ÐµÑ\81Ñ\82кÑ\96 Ð¿Ñ\80а ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80"
 
 #: src/hostname/org.freedesktop.hostname1.policy:42
 msgid "Authentication is required to set local machine information."
-msgstr ""
-"Неабходна аўтэнтыфікацыя для ўсталявання інфармацыі аб лакальнай машыне."
+msgstr "Для наладкі звестак пра камп’ютар патрабуецца аўтэнтыфікацыя."
 
 #: src/hostname/org.freedesktop.hostname1.policy:51
 msgid "Get product UUID"
-msgstr ""
+msgstr "Атрымаць UUID прадукту"
 
 #: src/hostname/org.freedesktop.hostname1.policy:52
-#, fuzzy
-#| msgid "Authentication is required to reload '$(unit)'."
 msgid "Authentication is required to get product UUID."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð°Ñ\82Ñ\80Ñ\8bманнÑ\8f UUID Ð¿Ñ\80адÑ\83кÑ\82Ñ\83 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/import/org.freedesktop.import1.policy:22
 msgid "Import a VM or container image"
-msgstr "Ð\86мпаÑ\80Ñ\82аваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð\92Ð\9c або кантэйнера"
+msgstr "Ð\86мпаÑ\80Ñ\82аваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнай Ð¼Ð°Ñ\88Ñ\8bнÑ\8b або кантэйнера"
 
 #: src/import/org.freedesktop.import1.policy:23
 msgid "Authentication is required to import a VM or container image"
-msgstr "Неабходна аўтэнтыфікацыя для імпарту вобраза ВМ або кантэйнера"
+msgstr ""
+"Для імпарту вобраза віртуальнай машыны або кантэйнера патрабуецца "
+"аўтэнтыфікацыя"
 
 #: src/import/org.freedesktop.import1.policy:32
 msgid "Export a VM or container image"
-msgstr "ЭкÑ\81паÑ\80Ñ\82аваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð\92Ð\9c або кантэйнера"
+msgstr "ЭкÑ\81паÑ\80Ñ\82аваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнай Ð¼Ð°Ñ\88Ñ\8bнÑ\8b або кантэйнера"
 
 #: src/import/org.freedesktop.import1.policy:33
 msgid "Authentication is required to export a VM or container image"
-msgstr "Неабходна аўтэнтыфікацыя для экспарту вобраза ВМ або кантэйнера"
+msgstr ""
+"Для экспарту вобраза віртуальнай машыны або кантэйнера патрабуецца "
+"аўтэнтыфікацыя"
 
 #: src/import/org.freedesktop.import1.policy:42
 msgid "Download a VM or container image"
-msgstr "СпампаваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð\92Ð\9c або кантэйнера"
+msgstr "СпампаваÑ\86Ñ\8c Ð²Ð¾Ð±Ñ\80аз Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнай Ð¼Ð°Ñ\88Ñ\8bнÑ\8b або кантэйнера"
 
 #: src/import/org.freedesktop.import1.policy:43
 msgid "Authentication is required to download a VM or container image"
-msgstr "Неабходна аўтэнтыфікацыя для спампоўкі вобраза ВМ або кантэйнера"
+msgstr ""
+"Для спампоўвання вобраза віртуальнай машыны або кантэйнера патрабуецца "
+"аўтэнтыфікацыя"
 
 #: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
-msgstr "УÑ\81Ñ\82алÑ\8fваць сістэмную лакаль"
+msgstr "Ð\9dаладзÑ\96ць сістэмную лакаль"
 
 #: src/locale/org.freedesktop.locale1.policy:23
 msgid "Authentication is required to set the system locale."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнай Ð»Ð°ÐºÐ°Ð»Ñ\96."
+msgstr "Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнай Ð»Ð°ÐºÐ°Ð»Ñ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/locale/org.freedesktop.locale1.policy:33
 msgid "Set system keyboard settings"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bÑ\8f Ð½Ð°Ð»Ð°Ð´ы клавіятуры"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ð¿Ð°Ñ\80амеÑ\82Ñ\80ы клавіятуры"
 
 #: src/locale/org.freedesktop.locale1.policy:34
 msgid "Authentication is required to set the system keyboard settings."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8bÑ\85 Ð½Ð°Ð»Ð°Ð´ ÐºÐ»Ð°Ð²Ñ\96Ñ\8fÑ\82Ñ\83Ñ\80Ñ\8b."
+msgstr "Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ð¿Ð°Ñ\80амеÑ\82Ñ\80аÑ\9e ÐºÐ»Ð°Ð²Ñ\96Ñ\8fÑ\82Ñ\83Ñ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:22
 msgid "Allow applications to inhibit system shutdown"
@@ -224,8 +211,8 @@ msgstr "Дазволіць праграмам перашкаджаць выкл
 msgid ""
 "Authentication is required for an application to inhibit system shutdown."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e "
-"сістэмы."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:33
 msgid "Allow applications to delay system shutdown"
@@ -234,28 +221,28 @@ msgstr "Дазволіць праграмам затрымліваць выкл
 #: src/login/org.freedesktop.login1.policy:34
 msgid "Authentication is required for an application to delay system shutdown."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dнне "
-"сістэмы."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dнне Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:44
 msgid "Allow applications to inhibit system sleep"
-msgstr "Ð\94азволÑ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð·Ð°Ñ\81Ñ\8bпаннÑ\8e Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b"
+msgstr "Ð\94азволÑ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð¿ÐµÑ\80аÑ\85одÑ\83 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83"
 
 #: src/login/org.freedesktop.login1.policy:45
 msgid "Authentication is required for an application to inhibit system sleep."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð·Ð°Ñ\81Ñ\8bпаннÑ\8e "
-"сістэмы."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð¿ÐµÑ\80аÑ\85одÑ\83 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83, "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:55
 msgid "Allow applications to delay system sleep"
-msgstr "Ð\94азволÑ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð·Ð°Ñ\81Ñ\8bпанне Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b"
+msgstr "Ð\94азволÑ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð¿ÐµÑ\80аÑ\85од Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83"
 
 #: src/login/org.freedesktop.login1.policy:56
 msgid "Authentication is required for an application to delay system sleep."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð·Ð°Ñ\81Ñ\8bпанне "
-"сістэмы."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð·Ð°Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\86Ñ\8c Ð¿ÐµÑ\80аÑ\85од Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83, "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:65
 msgid "Allow applications to inhibit automatic system suspend"
@@ -266,82 +253,78 @@ msgid ""
 "Authentication is required for an application to inhibit automatic system "
 "suspend."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð°Ñ\9eÑ\82амаÑ\82Ñ\8bÑ\87намÑ\83 "
-"прыпыненню сістэмы."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ð°Ñ\9eÑ\82амаÑ\82Ñ\8bÑ\87намÑ\83 Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8e "
+"сістэмы, патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:75
 msgid "Allow applications to inhibit system handling of the power key"
-msgstr ""
-"Дазволіць праграмам перашкаджаць сістэме апрацоўваць клавішу выключэння"
+msgstr "Дазволіць праграмам перашкаджаць сістэме апрацоўваць кнопку выключэння"
 
 #: src/login/org.freedesktop.login1.policy:76
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the power key."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме "
-"апÑ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ»Ð°Ð²Ñ\96Ñ\88Ñ\83 Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dння."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме Ð°Ð¿Ñ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ½Ð¾Ð¿ÐºÑ\83 "
+"вÑ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bя."
 
 #: src/login/org.freedesktop.login1.policy:86
 msgid "Allow applications to inhibit system handling of the suspend key"
-msgstr ""
-"Дазволіць праграмам перашкаджаць сістэме апрацоўваць клавішу прыпынення"
+msgstr "Дазволіць праграмам перашкаджаць сістэме апрацоўваць кнопку прыпынення"
 
 #: src/login/org.freedesktop.login1.policy:87
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the suspend key."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме "
-"апÑ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ»Ð°Ð²Ñ\96Ñ\88Ñ\83 Ð¿Ñ\80Ñ\8bпÑ\8bнення."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме Ð°Ð¿Ñ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ½Ð¾Ð¿ÐºÑ\83 "
+"пÑ\80Ñ\8bпÑ\8bненнÑ\8f, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bя."
 
 #: src/login/org.freedesktop.login1.policy:97
 msgid "Allow applications to inhibit system handling of the hibernate key"
 msgstr ""
-"Дазволіць праграмам перашкаджаць сістэме апрацоўваць клавішу гібернацыі"
+"Дазволіць праграмам перашкаджаць сістэме апрацоўваць кнопку пераходу ў рэжым "
+"сну"
 
 #: src/login/org.freedesktop.login1.policy:98
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the hibernate key."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме "
-"апÑ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ»Ð°Ð²Ñ\96Ñ\88Ñ\83 Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме Ð°Ð¿Ñ\80аÑ\86оÑ\9eваÑ\86Ñ\8c ÐºÐ½Ð¾Ð¿ÐºÑ\83 "
+"пеÑ\80аÑ\85одÑ\83 Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:107
 msgid "Allow applications to inhibit system handling of the lid switch"
-msgstr ""
-"Дазволіць праграмам перашкаджаць сістэме апрацоўваць закрыццё крышкі ноўтбука"
+msgstr "Дазволіць праграмам перашкаджаць сістэме апрацоўваць закрыццё ноўтбука"
 
 #: src/login/org.freedesktop.login1.policy:108
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the lid switch."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\83 Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме "
-"апÑ\80аÑ\86оÑ\9eваÑ\86Ñ\8c Ð·Ð°ÐºÑ\80Ñ\8bÑ\86Ñ\86Ñ\91 ÐºÑ\80Ñ\8bÑ\88кÑ\96 Ð½Ð¾Ñ\9eÑ\82бÑ\83ка."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿ÐµÑ\80аÑ\88каджаÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dме Ð°Ð¿Ñ\80аÑ\86оÑ\9eваÑ\86Ñ\8c Ð·Ð°ÐºÑ\80Ñ\8bÑ\86Ñ\86Ñ\91 "
+"ноÑ\9eÑ\82бÑ\83ка, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:117
 msgid "Allow non-logged-in user to run programs"
-msgstr ""
-"Дазволіць карыстальніку, якія яшчэ не ўвайшоў у сістэму, выконваць праграмы"
+msgstr "Дазволіць праграмам працаваць у фоне па-за сеансам карыстальніка"
 
 #: src/login/org.freedesktop.login1.policy:118
 msgid "Explicit request is required to run programs as a non-logged-in user."
 msgstr ""
-"Ð\9dеабÑ\85однÑ\8b Ð²Ñ\96давоÑ\87нÑ\8b Ð·Ð°Ð¿Ñ\8bÑ\82 Ð´Ð»Ñ\8f Ð²Ñ\8bкананнÑ\8f Ð¿Ñ\80агÑ\80ам ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96ка, Ñ\8fкÑ\96 Ñ\8fÑ\88Ñ\87Ñ\8d Ð½Ðµ "
-"ўвайшоў у сістэму."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿Ñ\80аÑ\86аваÑ\86Ñ\8c Ð¿Ð°-за Ñ\81еанÑ\81ам ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96ка, "
+"патрабуецца відавочны запыт."
 
 #: src/login/org.freedesktop.login1.policy:127
 msgid "Allow non-logged-in users to run programs"
-msgstr ""
-"Дазволіць карыстальнікам, якія яшчэ не ўвайшлі ў сістэму, выконваць праграмы"
+msgstr "Дазволіць праграмам працаваць у фоне па-за сеансам карыстальніка"
 
 #: src/login/org.freedesktop.login1.policy:128
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\8bкананнÑ\8f Ð¿Ñ\80агÑ\80ам ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96ка, Ñ\8fкÑ\96 Ñ\8fÑ\88Ñ\87Ñ\8d Ð½Ðµ "
-"ўвайшоў у сістэму."
+"Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ð¿Ñ\80агÑ\80амам Ð¿Ñ\80аÑ\86аваÑ\86Ñ\8c Ð¿Ð°-за Ð¼ÐµÐ¶Ð°Ð¼Ñ\96 Ñ\81еанÑ\81а "
+"карыстальніка, патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:137
 msgid "Allow attaching devices to seats"
@@ -349,15 +332,17 @@ msgstr "Дазволіць далучаць прылады да працоўны
 
 #: src/login/org.freedesktop.login1.policy:138
 msgid "Authentication is required to attach a device to a seat."
-msgstr "Неабходна аўтэнтыфікацыя для далучэння прылад да працоўных месцаў."
+msgstr ""
+"Для таго, каб дазволіць далучаць прылады да працоўных месцаў, патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:148
 msgid "Flush device to seat attachments"
-msgstr "Ð\90дклÑ\8eÑ\87аць прылады ад працоўных месцаў"
+msgstr "Ð\90длÑ\83Ñ\87Ñ\8bць прылады ад працоўных месцаў"
 
 #: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to reset how devices are attached to seats."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð°Ð´ÐºÐ»Ñ\8eÑ\87Ñ\8dннÑ\8f Ð¿Ñ\80Ñ\8bлад Ð°Ð´ Ð¿Ñ\80аÑ\86оÑ\9eнÑ\8bÑ\85 Ð¼ÐµÑ\81Ñ\86аÑ\9e."
+msgstr "Ð\94лÑ\8f Ð°Ð´Ð»Ñ\83Ñ\87Ñ\8dннÑ\8f Ð¿Ñ\80Ñ\8bлад Ð°Ð´ Ð¿Ñ\80аÑ\86оÑ\9eнÑ\8bÑ\85 Ð¼ÐµÑ\81Ñ\86аÑ\9e Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:158
 msgid "Power off the system"
@@ -365,19 +350,19 @@ msgstr "Выключыць сістэму"
 
 #: src/login/org.freedesktop.login1.policy:159
 msgid "Authentication is required to power off the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:169
 msgid "Power off the system while other users are logged in"
-msgstr "Ð\92Ñ\8bклÑ\8eÑ\87Ñ\8bÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e"
+msgstr "Ð\92Ñ\8bклÑ\8eÑ\87Ñ\8bÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96"
 
 #: src/login/org.freedesktop.login1.policy:170
 msgid ""
 "Authentication is required to power off the system while other users are "
 "logged in."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 "
-"каÑ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e."
+"Ð\94лÑ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:180
 msgid "Power off the system while an application is inhibiting this"
@@ -388,8 +373,8 @@ msgid ""
 "Authentication is required to power off the system while an application is "
 "inhibiting this."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, ÐºÐ°Ð»Ñ\96 Ð¿Ñ\80агÑ\80амÑ\8b перашкаджаюць "
-"гÑ\8dÑ\82амÑ\83."
+"Ð\94лÑ\8f Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ð¿Ñ\80агÑ\80амамÑ\96, Ñ\8fкÑ\96Ñ\8f перашкаджаюць "
+"вÑ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:191
 msgid "Reboot the system"
@@ -397,19 +382,19 @@ msgstr "Перазагрузіць сістэму"
 
 #: src/login/org.freedesktop.login1.policy:192
 msgid "Authentication is required to reboot the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:202
 msgid "Reboot the system while other users are logged in"
-msgstr "Ð\9fеÑ\80азагÑ\80Ñ\83зÑ\96Ñ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e"
+msgstr "Ð\9fеÑ\80азагÑ\80Ñ\83зÑ\96Ñ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96"
 
 #: src/login/org.freedesktop.login1.policy:203
 msgid ""
 "Authentication is required to reboot the system while other users are logged "
 "in."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 "
-"каÑ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e."
+"Ð\94лÑ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:213
 msgid "Reboot the system while an application is inhibiting this"
@@ -420,56 +405,40 @@ msgid ""
 "Authentication is required to reboot the system while an application is "
 "inhibiting this."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, ÐºÐ°Ð»Ñ\96 Ð¿Ñ\80агÑ\80амÑ\8b "
-"пеÑ\80аÑ\88каджаÑ\8eÑ\86Ñ\8c Ð³Ñ\8dÑ\82амÑ\83."
+"Ð\94лÑ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ð¿Ñ\80агÑ\80амамÑ\96, Ñ\8fкÑ\96Ñ\8f Ð¿ÐµÑ\80аÑ\88каджаÑ\8eÑ\86Ñ\8c "
+"вÑ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:224
-#, fuzzy
-#| msgid "Hibernate the system"
 msgid "Halt the system"
-msgstr "Ð\93Ñ\96беÑ\80наваць сістэму"
+msgstr "СпÑ\8bнÑ\96ць сістэму"
 
 #: src/login/org.freedesktop.login1.policy:225
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to halt the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ñ\81пÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:235
-#, fuzzy
-#| msgid "Hibernate the system while other users are logged in"
 msgid "Halt the system while other users are logged in"
-msgstr "Ð\93Ñ\96беÑ\80наваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e"
+msgstr "СпÑ\8bнÑ\96Ñ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96"
 
 #: src/login/org.freedesktop.login1.policy:236
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while other users are "
-#| "logged in."
 msgid ""
 "Authentication is required to halt the system while other users are logged "
 "in."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 "
-"каÑ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e."
+"Ð\94лÑ\8f Ñ\81пÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:246
-#, fuzzy
-#| msgid "Hibernate the system while an application is inhibiting this"
 msgid "Halt the system while an application is inhibiting this"
-msgstr "Ð\93Ñ\96беÑ\80наваць сістэму, калі праграмы перашкаджаюць гэтаму"
+msgstr "СпÑ\8bнÑ\96ць сістэму, калі праграмы перашкаджаюць гэтаму"
 
 #: src/login/org.freedesktop.login1.policy:247
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while an application "
-#| "is inhibiting this."
 msgid ""
 "Authentication is required to halt the system while an application is "
 "inhibiting this."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, ÐºÐ°Ð»Ñ\96 Ð¿Ñ\80агÑ\80амÑ\8b Ð¿ÐµÑ\80аÑ\88каджаÑ\8eÑ\86Ñ\8c "
-"гÑ\8dÑ\82амÑ\83."
+"Ð\94лÑ\8f Ñ\81пÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ð¿Ñ\80агÑ\80амамÑ\96, Ñ\8fкÑ\96Ñ\8f Ð¿ÐµÑ\80аÑ\88каджаÑ\8eÑ\86Ñ\8c Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e, "
+"паÑ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:257
 msgid "Suspend the system"
@@ -477,19 +446,19 @@ msgstr "Прыпыніць сістэму"
 
 #: src/login/org.freedesktop.login1.policy:258
 msgid "Authentication is required to suspend the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:267
 msgid "Suspend the system while other users are logged in"
-msgstr "Ð\9fÑ\80Ñ\8bпÑ\8bнÑ\96Ñ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e"
+msgstr "Ð\9fÑ\80Ñ\8bпÑ\8bнÑ\96Ñ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96"
 
 #: src/login/org.freedesktop.login1.policy:268
 msgid ""
 "Authentication is required to suspend the system while other users are "
 "logged in."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 "
-"каÑ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e."
+"Ð\94лÑ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:278
 msgid "Suspend the system while an application is inhibiting this"
@@ -500,130 +469,119 @@ msgid ""
 "Authentication is required to suspend the system while an application is "
 "inhibiting this."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, ÐºÐ°Ð»Ñ\96 Ð¿Ñ\80агÑ\80амÑ\8b перашкаджаюць "
-"гÑ\8dÑ\82амÑ\83."
+"Ð\94лÑ\8f Ð¿Ñ\80Ñ\8bпÑ\8bненнÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð· Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ð¿Ñ\80агÑ\80амамÑ\96, Ñ\8fкÑ\96Ñ\8f перашкаджаюць "
+"вÑ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:289
 msgid "Hibernate the system"
-msgstr "Ð\93Ñ\96беÑ\80наваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dму"
+msgstr "Ð\9fеÑ\80авеÑ\81Ñ\86Ñ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81ну"
 
 #: src/login/org.freedesktop.login1.policy:290
 msgid "Authentication is required to hibernate the system."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ð¿ÐµÑ\80аводÑ\83 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:299
 msgid "Hibernate the system while other users are logged in"
-msgstr "Ð\93Ñ\96беÑ\80наваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e"
+msgstr "Ð\9fеÑ\80авеÑ\81Ñ\86Ñ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96"
 
 #: src/login/org.freedesktop.login1.policy:300
 msgid ""
 "Authentication is required to hibernate the system while other users are "
 "logged in."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ð¿Ñ\80Ñ\8b Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82наÑ\81Ñ\86Ñ\96 Ñ\96нÑ\88Ñ\8bÑ\85 "
-"каÑ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96каÑ\9e."
+"Ð\94лÑ\8f Ð¿ÐµÑ\80аводÑ\83 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83 Ð· Ñ\96нÑ\88Ñ\8bмÑ\96 Ð¿Ñ\80Ñ\8bÑ\81Ñ\83Ñ\82нÑ\8bмÑ\96 ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 "
+"паÑ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while an application is inhibiting this"
-msgstr "Ð\93Ñ\96беÑ\80наваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dму, калі праграмы перашкаджаюць гэтаму"
+msgstr "Ð\9fеÑ\80авеÑ\81Ñ\86Ñ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\83 Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81ну, калі праграмы перашкаджаюць гэтаму"
 
 #: src/login/org.freedesktop.login1.policy:311
 msgid ""
 "Authentication is required to hibernate the system while an application is "
 "inhibiting this."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b, ÐºÐ°Ð»Ñ\96 Ð¿Ñ\80агÑ\80амÑ\8b перашкаджаюць "
-"гÑ\8dÑ\82амÑ\83."
+"Ð\94лÑ\8f Ð¿ÐµÑ\80аводÑ\83 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b Ñ\9e Ñ\80Ñ\8dжÑ\8bм Ñ\81нÑ\83 Ð· Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ð¿Ñ\80агÑ\80амамÑ\96, Ñ\8fкÑ\96Ñ\8f перашкаджаюць "
+"вÑ\8bклÑ\8eÑ\87Ñ\8dннÑ\8e, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:321
 msgid "Manage active sessions, users and seats"
-msgstr "Кіраваць актыўнымі сесіямі, карыстальнікамі і працоўнымі месцамі"
+msgstr "Кіраванне актыўнымі сеансамі, карыстальнікамі і працоўнымі месцамі"
 
 #: src/login/org.freedesktop.login1.policy:322
 msgid "Authentication is required to manage active sessions, users and seats."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ñ\81еÑ\81Ñ\96Ñ\8fмÑ\96, ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 і "
-"меÑ\81Ñ\86амÑ\96."
+"Ð\94лÑ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bмÑ\96 Ñ\81еанÑ\81амÑ\96, ÐºÐ°Ñ\80Ñ\8bÑ\81Ñ\82алÑ\8cнÑ\96камÑ\96 Ñ\96 Ð¿Ñ\80аÑ\86оÑ\9eнÑ\8bмÑ\96 Ð¼ÐµÑ\81Ñ\86амі "
+"паÑ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/login/org.freedesktop.login1.policy:331
 msgid "Lock or unlock active sessions"
-msgstr "Ð\91лакаваÑ\86Ñ\8c Ð°Ð±Ð¾ Ñ\80азблакаваÑ\86Ñ\8c Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\83Ñ\8e Ñ\81еÑ\81Ñ\96Ñ\8e"
+msgstr "Ð\97аблакаваÑ\86Ñ\8c Ð°Ð±Ð¾ Ñ\80азблакаваÑ\86Ñ\8c Ð°ÐºÑ\82Ñ\8bÑ\9eнÑ\8bÑ\8f Ñ\81еанÑ\81Ñ\8b"
 
 #: src/login/org.freedesktop.login1.policy:332
 msgid "Authentication is required to lock or unlock active sessions."
 msgstr ""
-"Неабходна аўтэнтыфікацыя для блакіроўкі або разблакіроўкі актыўнай сесіі."
+"Для таго, каб заблакаваць ці разблакаваць актыўныя сеансы, патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:341
 msgid "Set the reboot \"reason\" in the kernel"
-msgstr ""
+msgstr "Вызначыць \"прычыну\" перазапуску"
 
 #: src/login/org.freedesktop.login1.policy:342
-#, fuzzy
-#| msgid "Authentication is required to set the system timezone."
 msgid "Authentication is required to set the reboot \"reason\" in the kernel."
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання сістэмнага часавога поясу."
+msgstr ""
+"Для таго, каб вызначыць прычыну перазапуску, патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:352
-#, fuzzy
-#| msgid "Allow indication to the firmware to boot to setup interface"
 msgid "Indicate to the firmware to boot to setup interface"
-msgstr "Ð\94азволÑ\96Ñ\86Ñ\8c Ñ\83казанне Ð¿Ñ\80аÑ\88Ñ\8bÑ\9eÑ\86Ñ\8b Ð½Ð° Ð·Ð°Ð³Ñ\80Ñ\83зкÑ\83 Ñ\96нÑ\82Ñ\8dÑ\80Ñ\84ейÑ\81Ñ\83 Ð½Ð°Ð»Ð°Ð´"
+msgstr "Ð\97апÑ\83Ñ\81Ñ\86Ñ\96Ñ\86Ñ\8c Ð½Ð°Ð»Ð°Ð´ÐºÑ\83 Ð¿Ñ\80аÑ\88Ñ\8bÑ\9eкÑ\96 Ð¿Ð°Ð´Ñ\87аÑ\81 Ð½Ð°Ñ\81Ñ\82Ñ\83пнага Ð·Ð°Ð¿Ñ\83Ñ\81кÑ\83"
 
 #: src/login/org.freedesktop.login1.policy:353
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
-msgstr ""
-"Неабходна аўтэнтыфікацыя для ўказання прашыўцы на загрузку інтэрфейсу налад."
+msgstr "Для таго, каб запусціць наладку прашыўкі, патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:363
 msgid "Indicate to the boot loader to boot to the boot loader menu"
-msgstr ""
+msgstr "Вывесці меню загрузчыка падчас наступнага запуску"
 
 #: src/login/org.freedesktop.login1.policy:364
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
 msgid ""
 "Authentication is required to indicate to the boot loader to boot to the "
 "boot loader menu."
 msgstr ""
-"Неабходна аўтэнтыфікацыя для ўказання прашыўцы на загрузку інтэрфейсу налад."
+"Для вываду меню загрузчыка падчас наступнага запуску патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:374
 msgid "Indicate to the boot loader to boot a specific entry"
-msgstr ""
+msgstr "Абраць пэўны загрузачны запіс падчас наступнага запуску"
 
 #: src/login/org.freedesktop.login1.policy:375
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
 msgid ""
 "Authentication is required to indicate to the boot loader to boot into a "
 "specific boot loader entry."
 msgstr ""
-"Неабходна аўтэнтыфікацыя для ўказання прашыўцы на загрузку інтэрфейсу налад."
+"Для таго, каб абраць пэўны загрузачны запіс падчас наступнага запуску, "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/login/org.freedesktop.login1.policy:385
 msgid "Set a wall message"
-msgstr "УÑ\81Ñ\82алÑ\8fваць усеагульнае паведамленне"
+msgstr "Ð\92Ñ\8bзнаÑ\87Ñ\8bць усеагульнае паведамленне"
 
 #: src/login/org.freedesktop.login1.policy:386
 msgid "Authentication is required to set a wall message"
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½я"
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bзнаÑ\87Ñ\8dннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½Ñ\8f Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bя"
 
 #: src/login/org.freedesktop.login1.policy:395
 msgid "Change Session"
-msgstr ""
+msgstr "Змяніць сеанс"
 
 #: src/login/org.freedesktop.login1.policy:396
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to change the virtual terminal."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\96мÑ\8f Ð²Ñ\83зла."
+msgstr "Ð\94лÑ\8f Ð·Ð¼ÐµÐ½Ñ\8b Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнага Ñ\81еанÑ\81а Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/machine/org.freedesktop.machine1.policy:22
 msgid "Log into a local container"
@@ -631,329 +589,297 @@ msgstr "Увайсці ў лакальны кантэйнер"
 
 #: src/machine/org.freedesktop.machine1.policy:23
 msgid "Authentication is required to log into a local container."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eваÑ\85одÑ\83 Ñ\9e Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8b ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80."
+msgstr "Ð\94лÑ\8f Ñ\9eваÑ\85одÑ\83 Ñ\9e Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8b ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/machine/org.freedesktop.machine1.policy:32
 msgid "Log into the local host"
-msgstr "Увайсці ў лакальны вузел"
+msgstr "Увайсці на лакальны камп’ютар"
 
 #: src/machine/org.freedesktop.machine1.policy:33
 msgid "Authentication is required to log into the local host."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eваÑ\85одÑ\83 Ñ\9e Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8b Ð²Ñ\83зел."
+msgstr "Ð\94лÑ\8f Ñ\9eваÑ\85одÑ\83 Ð½Ð° Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8b ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/machine/org.freedesktop.machine1.policy:42
 msgid "Acquire a shell in a local container"
-msgstr "Атрымаць абалонку на лакальным кантэйнеры"
+msgstr "Атрымаць абалонку ў лакальным кантэйнеры"
 
 #: src/machine/org.freedesktop.machine1.policy:43
 msgid "Authentication is required to acquire a shell in a local container."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð°Ñ\82Ñ\80Ñ\8bманнÑ\8f Ð°Ð±Ð°Ð»Ð¾Ð½ÐºÑ\96 Ð½Ð° Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bм ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80Ñ\8b."
+"Ð\94лÑ\8f Ð°Ñ\82Ñ\80Ñ\8bманнÑ\8f Ð°Ð±Ð°Ð»Ð¾Ð½ÐºÑ\96 Ñ\9e Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bм ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/machine/org.freedesktop.machine1.policy:53
 msgid "Acquire a shell on the local host"
-msgstr "Ð\90Ñ\82Ñ\80Ñ\8bмаÑ\86Ñ\8c Ð°Ð±Ð°Ð»Ð¾Ð½ÐºÑ\83 Ð½Ð° Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bм Ð²Ñ\83зле"
+msgstr "Ð\90Ñ\82Ñ\80Ñ\8bмаÑ\86Ñ\8c Ð°Ð±Ð°Ð»Ð¾Ð½ÐºÑ\83 Ð½Ð° Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bм ÐºÐ°Ð¼Ð¿â\80\99Ñ\8eÑ\82аÑ\80Ñ\8b"
 
 #: src/machine/org.freedesktop.machine1.policy:54
 msgid "Authentication is required to acquire a shell on the local host."
-msgstr "Неабходна аўтэнтыфікацыя для атрымання абалонкі на лакальным вузле."
+msgstr ""
+"Для атрымання абалонкі на лакальным камп’ютары патрабуецца аўтэнтыфікацыя."
 
 #: src/machine/org.freedesktop.machine1.policy:64
 msgid "Acquire a pseudo TTY in a local container"
-msgstr "Атрымаць псеўда TTY на лакальным кантэйнеры"
+msgstr "Атрымаць псеўда-тэрмінал у лакальным кантэйнеры"
 
 #: src/machine/org.freedesktop.machine1.policy:65
 msgid ""
 "Authentication is required to acquire a pseudo TTY in a local container."
 msgstr ""
-"Неабходна аўтэнтыфікацыя для атрымання псеўда TTY на лакальным кантэйнеры."
+"Для атрымання псеўда-тэрмінала ў лакальным кантэйнеры патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/machine/org.freedesktop.machine1.policy:74
 msgid "Acquire a pseudo TTY on the local host"
-msgstr "Атрымаць псеўда TTY на лакальным вузле"
+msgstr "Атрымаць псеўда-тэрмінал на лакальным камп’ютары"
 
 #: src/machine/org.freedesktop.machine1.policy:75
 msgid "Authentication is required to acquire a pseudo TTY on the local host."
-msgstr "Неабходна аўтэнтыфікацыя для атрымання псеўда TTY на лакальным вузле."
+msgstr ""
+"Для атрымання псеўда-тэрмінала на лакальным камп’ютары патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/machine/org.freedesktop.machine1.policy:84
 msgid "Manage local virtual machines and containers"
-msgstr "Кіраваць лакальнымі віртуальнымі машынамі або кантэйнерамі"
+msgstr "Кіраванне лакальнымі віртуальнымі машынамі або кантэйнерамі"
 
 #: src/machine/org.freedesktop.machine1.policy:85
 msgid ""
 "Authentication is required to manage local virtual machines and containers."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bмÑ\96 Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнÑ\8bмÑ\96 Ð¼Ð°Ñ\88Ñ\8bнамÑ\96 Ñ\96 "
-"канÑ\82Ñ\8dйнеÑ\80амÑ\96."
+"Ð\94лÑ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bмÑ\96 Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнÑ\8bмÑ\96 Ð¼Ð°Ñ\88Ñ\8bнамÑ\96 Ñ\96 ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80амÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аÑ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/machine/org.freedesktop.machine1.policy:95
 msgid "Manage local virtual machine and container images"
-msgstr "Кіраваць вобразамі лакальных віртуальных машын і кантэйнераў"
+msgstr "Кіраванне вобразамі лакальных віртуальных машын і кантэйнераў"
 
 #: src/machine/org.freedesktop.machine1.policy:96
 msgid ""
 "Authentication is required to manage local virtual machine and container "
 "images."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð²Ð¾Ð±Ñ\80азамÑ\96 Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bÑ\85 Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнÑ\8bÑ\85 Ð¼Ð°Ñ\88Ñ\8bн "
-"і кантэйнераў."
+"Ð\94лÑ\8f ÐºÑ\96Ñ\80аваннÑ\8f Ð²Ð¾Ð±Ñ\80азамÑ\96 Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8bÑ\85 Ð²Ñ\96Ñ\80Ñ\82Ñ\83алÑ\8cнÑ\8bÑ\85 Ð¼Ð°Ñ\88Ñ\8bн Ñ\96 ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80аÑ\9e "
+"патрабуецца аўтэнтыфікацыя."
 
 #: src/network/org.freedesktop.network1.policy:22
 msgid "Set NTP servers"
-msgstr ""
+msgstr "Вызначыць серверы NTP"
 
 #: src/network/org.freedesktop.network1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to set NTP servers."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bзнаÑ\87Ñ\8dннÑ\8f Ñ\81еÑ\80веÑ\80аÑ\9e NTP Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:33
 #: src/resolve/org.freedesktop.resolve1.policy:44
 msgid "Set DNS servers"
-msgstr ""
+msgstr "Вызначыць серверы DNS"
 
 #: src/network/org.freedesktop.network1.policy:34
 #: src/resolve/org.freedesktop.resolve1.policy:45
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to set DNS servers."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bзнаÑ\87Ñ\8dннÑ\8f Ñ\81еÑ\80веÑ\80аÑ\9e DNS Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:44
 #: src/resolve/org.freedesktop.resolve1.policy:55
 msgid "Set domains"
-msgstr ""
+msgstr "Вызначыць дамены"
 
 #: src/network/org.freedesktop.network1.policy:45
 #: src/resolve/org.freedesktop.resolve1.policy:56
-#, fuzzy
-#| msgid "Authentication is required to stop '$(unit)'."
 msgid "Authentication is required to set domains."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\81пÑ\8bненнÑ\8f '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bзнаÑ\87Ñ\8dннÑ\8f Ð´Ð°Ð¼ÐµÐ½Ð°Ñ\9e Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:55
 #: src/resolve/org.freedesktop.resolve1.policy:66
 msgid "Set default route"
-msgstr ""
+msgstr "Вызначыць прадвызначаны маршрут"
 
 #: src/network/org.freedesktop.network1.policy:56
 #: src/resolve/org.freedesktop.resolve1.policy:67
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to set default route."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\96мÑ\8f Ð²Ñ\83зла."
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bзнаÑ\87Ñ\8dннÑ\8f Ð¿Ñ\80адвÑ\8bзнаÑ\87анага Ð¼Ð°Ñ\80Ñ\88Ñ\80Ñ\83Ñ\82Ñ\83 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:66
 #: src/resolve/org.freedesktop.resolve1.policy:77
 msgid "Enable/disable LLMNR"
-msgstr ""
+msgstr "Уключыць / адключыць LLMNR"
 
 #: src/network/org.freedesktop.network1.policy:67
 #: src/resolve/org.freedesktop.resolve1.policy:78
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to enable or disable LLMNR."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\86Ñ\96 Ð°Ð´ÐºÐ»Ñ\8eÑ\87Ñ\8dннÑ\8f LLMNR Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:77
 #: src/resolve/org.freedesktop.resolve1.policy:88
 msgid "Enable/disable multicast DNS"
-msgstr ""
+msgstr "Уключыць / адключыць multicast DNS"
 
 #: src/network/org.freedesktop.network1.policy:78
 #: src/resolve/org.freedesktop.resolve1.policy:89
-#, fuzzy
-#| msgid "Authentication is required to log into the local host."
 msgid "Authentication is required to enable or disable multicast DNS."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eваÑ\85одÑ\83 Ñ\9e Ð»Ð°ÐºÐ°Ð»Ñ\8cнÑ\8b Ð²Ñ\83зел."
+msgstr "Ð\94лÑ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\86Ñ\96 Ð°Ð´ÐºÐ»Ñ\8eÑ\87Ñ\8dннÑ\8f multicast DNS Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:88
 #: src/resolve/org.freedesktop.resolve1.policy:99
 msgid "Enable/disable DNS over TLS"
-msgstr ""
+msgstr "Уключыць / адключыць DNS паверх TLS"
 
 #: src/network/org.freedesktop.network1.policy:89
 #: src/resolve/org.freedesktop.resolve1.policy:100
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to enable or disable DNS over TLS."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\96мÑ\8f Ð²Ñ\83зла."
+msgstr "Ð\94лÑ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\86Ñ\96 Ð°Ð´ÐºÐ»Ñ\8eÑ\87Ñ\8dннÑ\8f DNS Ð¿Ð°Ð²ÐµÑ\80Ñ\85 TLS Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:99
 #: src/resolve/org.freedesktop.resolve1.policy:110
 msgid "Enable/disable DNSSEC"
-msgstr ""
+msgstr "Уключыць / адключыць DNSSEC"
 
 #: src/network/org.freedesktop.network1.policy:100
 #: src/resolve/org.freedesktop.resolve1.policy:111
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to enable or disable DNSSEC."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð³Ñ\96беÑ\80наÑ\86Ñ\8bÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\86Ñ\96 Ð°Ð´ÐºÐ»Ñ\8eÑ\87Ñ\8dннÑ\8f DNSSEC Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:110
 #: src/resolve/org.freedesktop.resolve1.policy:121
 msgid "Set DNSSEC Negative Trust Anchors"
-msgstr ""
+msgstr "Вызначыць DNSSEC Negative Trust Anchors"
 
 #: src/network/org.freedesktop.network1.policy:111
 #: src/resolve/org.freedesktop.resolve1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system locale."
 msgid "Authentication is required to set DNSSEC Negative Trust Anchors."
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання сістэмнай лакалі."
+msgstr ""
+"Для вызначэння DNSSEC Negative Trust Anchors патрабуецца аўтэнтыфікацыя."
 
 #: src/network/org.freedesktop.network1.policy:121
 msgid "Revert NTP settings"
-msgstr ""
+msgstr "Скінуць налады NTP"
 
 #: src/network/org.freedesktop.network1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to reset NTP settings."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ñ\81кÑ\96нÑ\83Ñ\86Ñ\8c Ð½Ð°Ð»Ð°Ð´Ñ\8b NTP, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:132
 msgid "Revert DNS settings"
-msgstr ""
+msgstr "Скінуць налады DNS"
 
 #: src/network/org.freedesktop.network1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to reset DNS settings."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ñ\82аго, ÐºÐ°Ð± Ñ\81кÑ\96нÑ\83Ñ\86Ñ\8c Ð½Ð°Ð»Ð°Ð´Ñ\8b DNS, Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:143
 msgid "DHCP server sends force renew message"
-msgstr ""
+msgstr "Сервер DHCP адпраўляе паведамленне з прымусовым абнаўленнем"
 
 #: src/network/org.freedesktop.network1.policy:144
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to send force renew message."
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання ўсеагульнага паведамлення"
+msgstr ""
+"Для адпраўкі паведамлення з прымусовым абнаўленнем патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/network/org.freedesktop.network1.policy:154
 msgid "Renew dynamic addresses"
-msgstr ""
+msgstr "Абнавіць дынамічныя адрасы"
 
 #: src/network/org.freedesktop.network1.policy:155
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to renew dynamic addresses."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½Ñ\8f"
+msgstr "Ð\94лÑ\8f Ð°Ð±Ð½Ð°Ñ\9eленнÑ\8f Ð´Ñ\8bнамÑ\96Ñ\87нÑ\8bÑ\85 Ð°Ð´Ñ\80аÑ\81оÑ\9e Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:165
 msgid "Reload network settings"
-msgstr ""
+msgstr "Перазагрузіць налады сеткі"
 
 #: src/network/org.freedesktop.network1.policy:166
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to reload network settings."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 systemd."
+msgstr "Ð\94лÑ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ð½Ð°Ð»Ð°Ð´ Ñ\81еÑ\82кÑ\96 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/network/org.freedesktop.network1.policy:176
 msgid "Reconfigure network interface"
-msgstr ""
+msgstr "Змяніць канфігурацыю сеткавага інтэрфейсу"
 
 #: src/network/org.freedesktop.network1.policy:177
-#, fuzzy
-#| msgid "Authentication is required to reboot the system."
 msgid "Authentication is required to reconfigure network interface."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80азагÑ\80Ñ\83зкÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмÑ\8b."
+msgstr "Ð\94лÑ\8f Ð·Ð¼ÐµÐ½Ñ\8b ÐºÐ°Ð½Ñ\84Ñ\96гÑ\83Ñ\80аÑ\86Ñ\8bÑ\96 Ñ\81еÑ\82кавага Ñ\96нÑ\82Ñ\8dÑ\80Ñ\84ейÑ\81Ñ\83 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/portable/org.freedesktop.portable1.policy:13
 msgid "Inspect a portable service image"
-msgstr ""
+msgstr "Прачытаць вобраз пераноснай службы"
 
 #: src/portable/org.freedesktop.portable1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to import a VM or container image"
 msgid "Authentication is required to inspect a portable service image."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\96мпаÑ\80Ñ\82Ñ\83 Ð²Ð¾Ð±Ñ\80аза Ð\92Ð\9c Ð°Ð±Ð¾ ÐºÐ°Ð½Ñ\82Ñ\8dйнеÑ\80а"
+msgstr "Ð\94лÑ\8f Ñ\87Ñ\8bÑ\82аннÑ\8f Ð²Ð¾Ð±Ñ\80аза Ð¿ÐµÑ\80аноÑ\81най Ñ\81лÑ\83жбÑ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/portable/org.freedesktop.portable1.policy:23
 msgid "Attach or detach a portable service image"
-msgstr ""
+msgstr "Далучыць альбо адлучыць вобраз пераноснай службы"
 
 #: src/portable/org.freedesktop.portable1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
 msgid ""
 "Authentication is required to attach or detach a portable service image."
-msgstr "Неабходна аўтэнтыфікацыя для далучэння прылад да працоўных месцаў."
+msgstr ""
+"Для далучэння альбо адлучэння вобраза пераноснай службы патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/portable/org.freedesktop.portable1.policy:34
 msgid "Delete or modify portable service image"
-msgstr ""
+msgstr "Выдаліць альбо змяніць вобраз пераноснай службы"
 
 #: src/portable/org.freedesktop.portable1.policy:35
-#, fuzzy
-#| msgid "Authentication is required to download a VM or container image"
 msgid ""
 "Authentication is required to delete or modify a portable service image."
-msgstr "Неабходна аўтэнтыфікацыя для спампоўкі вобраза ВМ або кантэйнера"
+msgstr ""
+"Для выдалення альбо змены вобраза пераноснай службы патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/resolve/org.freedesktop.resolve1.policy:22
 msgid "Register a DNS-SD service"
-msgstr ""
+msgstr "Рэгістрацыя службы DNS-SD"
 
 #: src/resolve/org.freedesktop.resolve1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to register a DNS-SD service"
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½я"
+msgstr "Ð\94лÑ\8f Ñ\80Ñ\8dгÑ\96Ñ\81Ñ\82Ñ\80аÑ\86Ñ\8bÑ\96 Ñ\81лÑ\83жбÑ\8b DNS-SD Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bя"
 
 #: src/resolve/org.freedesktop.resolve1.policy:33
 msgid "Unregister a DNS-SD service"
-msgstr ""
+msgstr "Выдаленне службы DNS-SD"
 
 #: src/resolve/org.freedesktop.resolve1.policy:34
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to unregister a DNS-SD service"
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eÑ\81еагÑ\83лÑ\8cнага Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½я"
+msgstr "Ð\94лÑ\8f Ð²Ñ\8bдаленнÑ\8f Ñ\81лÑ\83жбÑ\8b DNS-SD Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bя"
 
 #: src/resolve/org.freedesktop.resolve1.policy:132
 msgid "Revert name resolution settings"
-msgstr ""
+msgstr "Скінуць налады вырашэння назваў"
 
 #: src/resolve/org.freedesktop.resolve1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system keyboard settings."
 msgid "Authentication is required to reset name resolution settings."
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання сістэмных налад клавіятуры."
+msgstr ""
+"Для таго, каб скінуць налады вырашэння назваў, патрабуецца аўтэнтыфікацыя."
 
 #: src/timedate/org.freedesktop.timedate1.policy:22
 msgid "Set system time"
-msgstr "УÑ\81Ñ\82алÑ\8fваць сістэмны час"
+msgstr "Ð\9dаладзÑ\96ць сістэмны час"
 
 #: src/timedate/org.freedesktop.timedate1.policy:23
 msgid "Authentication is required to set the system time."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81Ñ\83 Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/timedate/org.freedesktop.timedate1.policy:33
 msgid "Set system timezone"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнÑ\8b часавы пояс"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c часавы пояс"
 
 #: src/timedate/org.freedesktop.timedate1.policy:34
 msgid "Authentication is required to set the system timezone."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\81Ñ\96Ñ\81Ñ\82Ñ\8dмнага Ñ\87аÑ\81авога Ð¿Ð¾Ñ\8fÑ\81Ñ\83."
+msgstr "Ð\94лÑ\8f Ð½Ð°Ð»Ð°Ð´ÐºÑ\96 Ñ\87аÑ\81авога Ð¿Ð¾Ñ\8fÑ\81а Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/timedate/org.freedesktop.timedate1.policy:43
 msgid "Set RTC to local timezone or UTC"
-msgstr "УÑ\81Ñ\82алÑ\8fваÑ\86Ñ\8c Ñ\87аÑ\81авÑ\8b Ð¿Ð¾Ñ\8fÑ\81 (мÑ\8fÑ\81Ñ\86овÑ\8b Ð°Ð±Ð¾ UTC), Ñ\83 Ñ\8fкÑ\96м RTC Ð·Ð°Ñ\85оÑ\9eвае Ñ\87аÑ\81"
+msgstr "Ð\9dаладзÑ\96Ñ\86Ñ\8c Ð°Ð¿Ð°Ñ\80аÑ\82нÑ\8b Ð³Ð°Ð´Ð·Ñ\96ннÑ\96к Ð½Ð° Ð¼Ñ\8fÑ\81Ñ\86овÑ\8b Ñ\87аÑ\81 Ð°Ð»Ñ\8cбо UTC"
 
 #: src/timedate/org.freedesktop.timedate1.policy:44
 msgid ""
 "Authentication is required to control whether the RTC stores the local or "
 "UTC time."
-msgstr ""
-"Неабходна аўтэнтыфікацыя для ўсталявання часавога поясу (мясцовы або UTC), у "
-"якім захоўваецца час у RTC."
+msgstr "Для наладкі апаратнага гадзінніка патрабуецца аўтэнтыфікацыя."
 
 #: src/timedate/org.freedesktop.timedate1.policy:53
 msgid "Turn network time synchronization on or off"
@@ -964,57 +890,57 @@ msgid ""
 "Authentication is required to control whether network time synchronization "
 "shall be enabled."
 msgstr ""
-"Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ð°Ð±Ð¾ Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96нÑ\85Ñ\80анÑ\96заÑ\86Ñ\8bÑ\96 Ñ\87аÑ\81Ñ\83 Ð¿а "
-"сетцы."
+"Ð\94лÑ\8f Ñ\9eклÑ\8eÑ\87Ñ\8dннÑ\8f Ð°Ð±Ð¾ Ð²Ñ\8bклÑ\8eÑ\87Ñ\8dннÑ\8f Ñ\81Ñ\96нÑ\85Ñ\80анÑ\96заÑ\86Ñ\8bÑ\96 Ñ\87аÑ\81Ñ\83 Ð¿Ð° Ñ\81еÑ\82Ñ\86Ñ\8b Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а "
+"аўтэнтыфікацыя."
 
 #: src/core/dbus-unit.c:362
 msgid "Authentication is required to start '$(unit)'."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð·Ð°Ð¿Ñ\83Ñ\81кÑ\83 '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð·Ð°Ð¿Ñ\83Ñ\81кÑ\83 \"$(unit)\" Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/dbus-unit.c:363
 msgid "Authentication is required to stop '$(unit)'."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\81пÑ\8bненнÑ\8f '$(unit)'."
+msgstr "Ð\94лÑ\8f Ñ\81пÑ\8bненнÑ\8f \"$(unit)\" Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/dbus-unit.c:364
 msgid "Authentication is required to reload '$(unit)'."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð¿ÐµÑ\80аÑ\87Ñ\8bÑ\82аннÑ\8f Ñ\81Ñ\82анÑ\83 \"$(unit)\" Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366
 msgid "Authentication is required to restart '$(unit)'."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ð¿ÐµÑ\80азапÑ\83Ñ\81кÑ\83 '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð¿ÐµÑ\80азапÑ\83Ñ\81кÑ\83 \"$(unit)\" Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/dbus-unit.c:538
-#, fuzzy
-#| msgid "Authentication is required to set properties on '$(unit)'."
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання ўласцівасцей '$(unit)'."
+msgstr ""
+"Для адпраўкі сігналу UNIX працэсам адзінкі \"$(unit)\" патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/core/dbus-unit.c:569
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
-msgstr "Неабходна аўтэнтыфікацыя для анулявання памылковага стану '$(unit)'."
+msgstr ""
+"Для таго, каб скінуць стан \"failed\" у \"$(unit)\", патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/core/dbus-unit.c:602
 msgid "Authentication is required to set properties on '$(unit)'."
-msgstr "Ð\9dеабÑ\85одна Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f Ð´Ð»Ñ\8f Ñ\9eÑ\81Ñ\82алÑ\8fваннÑ\8f Ñ\9eлаÑ\81Ñ\86Ñ\96ваÑ\81Ñ\86ей '$(unit)'."
+msgstr "Ð\94лÑ\8f Ð·Ð¼ÐµÐ½Ñ\8b Ñ\9eлаÑ\81Ñ\86Ñ\96ваÑ\81Ñ\86ей \"$(unit)\" Ð¿Ð°Ñ\82Ñ\80абÑ\83еÑ\86Ñ\86а Ð°Ñ\9eÑ\82Ñ\8dнÑ\82Ñ\8bÑ\84Ñ\96каÑ\86Ñ\8bÑ\8f."
 
 #: src/core/dbus-unit.c:711
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
-msgstr "Неабходна аўтэнтыфікацыя для анулявання памылковага стану '$(unit)'."
+msgstr ""
+"Для выдалення файлаў і каталогаў, якія звязаныя з \"$(unit)\", патрабуецца "
+"аўтэнтыфікацыя."
 
 #: src/core/dbus-unit.c:760
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
-msgstr "Неабходна аўтэнтыфікацыя для анулявання памылковага стану '$(unit)'."
+msgstr ""
+"Для спынення альбо ўзнаўлення працэсаў \"$(unit)\" патрабуецца "
+"аўтэнтыфікацыя."
 
 #~ msgid "Authentication is required to kill '$(unit)'."
 #~ msgstr "Неабходна аўтэнтыфікацыя для забойства '$(unit)'."
index b3bf1b765e549fdce70dbc8c20c454b4ddbbaf5e..1dafbc5a5c24be910cc42706094bb03cb38af5ea 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -86,7 +86,7 @@ msgstr "Der kræves godkendelse for at fjerne en brugers hjemmeområde."
 msgid "Check credentials of a home area"
 msgstr "Tjek loginoplysninger for et hjemmeområde"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:34
 msgid ""
 "Authentication is required to check credentials against a user's home area."
@@ -98,7 +98,7 @@ msgstr ""
 msgid "Update a home area"
 msgstr "Opdater et hjemmeområde"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:44
 msgid "Authentication is required to update a user's home area."
 msgstr "Der kræves godkendelse for at opdatere en brugers hjemmeområde."
@@ -116,7 +116,7 @@ msgstr ""
 msgid "Change password of a home area"
 msgstr "Skift adgangskode for et hjemmeområde"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:64
 msgid ""
 "Authentication is required to change the password of a user's home area."
@@ -315,22 +315,22 @@ msgstr ""
 "Der kræves godkendelse for at brugere, som ikke er logget ind, kan køre "
 "programmer."
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:137
 msgid "Allow attaching devices to seats"
 msgstr "Tillad at montere af enheder til arbejdsstationer"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:138
 msgid "Authentication is required to attach a device to a seat."
 msgstr "Der kræves godkendelse for at montere en enhed til en arbejdsstation."
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:148
 msgid "Flush device to seat attachments"
 msgstr "Nulstil enhed monteret til en arbejdsstation"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to reset how devices are attached to seats."
 msgstr ""
@@ -502,7 +502,7 @@ msgstr ""
 msgid "Manage active sessions, users and seats"
 msgstr "Håndter aktive sessioner, brugere og arbejdsstationer"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:322
 msgid "Authentication is required to manage active sessions, users and seats."
 msgstr ""
@@ -802,7 +802,7 @@ msgstr ""
 msgid "Attach or detach a portable service image"
 msgstr "Tilslut eller frakobl et transportabel tjeneste-aftryk"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/portable/org.freedesktop.portable1.policy:24
 msgid ""
 "Authentication is required to attach or detach a portable service image."
index eac78e71fb8eb7de4a023f413d90705e7e2d9beb..59a27d2634789bc6b4f31cee39c45d7559d65cd7 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -94,7 +94,7 @@ msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig."
 msgid "Check credentials of a home area"
 msgstr ""
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:34
 #, fuzzy
 #| msgid ""
@@ -109,7 +109,7 @@ msgstr ""
 msgid "Update a home area"
 msgstr ""
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:44
 #, fuzzy
 #| msgid "Authentication is required to attach a device to a seat."
@@ -132,7 +132,7 @@ msgstr "Legitimierung ist zum Einstellen einer Nachricht an alle notwendig"
 msgid "Change password of a home area"
 msgstr ""
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/home/org.freedesktop.home1.policy:64
 #, fuzzy
 #| msgid ""
@@ -364,24 +364,24 @@ msgstr ""
 "Legitimierung ist erforderlich, damit nicht angemeldete Benutzer Programme "
 "ausführen dürfen."
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:137
 msgid "Allow attaching devices to seats"
 msgstr "Das Anschließen von Geräten an Arbeitsstationen erlauben"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:138
 msgid "Authentication is required to attach a device to a seat."
 msgstr ""
 "Legitimierung ist zum Anschließen eines Geräts an eine Arbeitsstation "
 "notwendig."
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:148
 msgid "Flush device to seat attachments"
 msgstr "Zurücksetzen der an eine Arbeitsstation angeschlossenen Geräte"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to reset how devices are attached to seats."
 msgstr ""
@@ -584,7 +584,7 @@ msgstr ""
 msgid "Manage active sessions, users and seats"
 msgstr "Aktive Sitzungen, Benutzer und Arbeitsstationen verwalten"
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/login/org.freedesktop.login1.policy:322
 msgid "Authentication is required to manage active sessions, users and seats."
 msgstr ""
@@ -941,7 +941,7 @@ msgstr ""
 msgid "Attach or detach a portable service image"
 msgstr ""
 
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
+# https://www.freedesktop.org/software/systemd/man/sd-login.html
 #: src/portable/org.freedesktop.portable1.policy:24
 #, fuzzy
 #| msgid "Authentication is required to attach a device to a seat."
index 365cd0bf89434d450e99c5219d0a3a84d411abd0..1c1c6a40d0cf32627b6b81277a60c6f68d8739d6 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -3,22 +3,20 @@
 # Italian translation for systemd package
 # Traduzione in italiano per il pacchetto systemd
 # Daniele Medri <dmedri@gmail.com>, 2013-2020.
-# Milo Casagrande <milo@milo.name>, 2020.
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
-"Report-Msgid-Bugs-To: \n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
 "POT-Creation-Date: 2020-08-19 18:02+0200\n"
-"PO-Revision-Date: 2020-09-15 08:29+0000\n"
-"Last-Translator: Milo Casagrande <milo@milo.name>\n"
-"Language-Team: Italian <https://translate.fedoraproject.org/projects/systemd/"
-"master/it/>\n"
+"PO-Revision-Date: 2020-10-03 09:52+0200\n"
+"Last-Translator: Daniele Medri <dmedri@gmail.com>\n"
 "Language: it\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2.2\n"
+"X-Generator: Poedit 2.2.1\n"
+"Language-Team: \n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -28,8 +26,7 @@ msgstr "Invia la frase segreta (passphrase) al sistema"
 msgid ""
 "Authentication is required to send the entered passphrase back to the system."
 msgstr ""
-"È richiesto autenticarsi per inviare la frase segreta (passphrase) al "
-"sistema."
+"Autenticazione richiesta per inviare la frase segreta (passphrase) al sistema."
 
 #: src/core/org.freedesktop.systemd1.policy.in:33
 msgid "Manage system services or other units"
@@ -38,7 +35,7 @@ msgstr "Gestisci i servizi o le altre unità di sistema"
 #: src/core/org.freedesktop.systemd1.policy.in:34
 msgid "Authentication is required to manage system services or other units."
 msgstr ""
-"È richiesto autenticarsi per gestire i servizi o le altre unità di sistema."
+"Autenticazione richiesta per gestire i servizi o le altre unità di sistema."
 
 #: src/core/org.freedesktop.systemd1.policy.in:43
 msgid "Manage system service or unit files"
@@ -47,7 +44,7 @@ msgstr "Gestisci i file dei servizi o delle unità di sistema"
 #: src/core/org.freedesktop.systemd1.policy.in:44
 msgid "Authentication is required to manage system service or unit files."
 msgstr ""
-"È richiesto autenticarsi per gestire i file dei servizi o delle unità di "
+"Autenticazione richiesta per gestire i file dei servizi o delle unità di "
 "sistema."
 
 #: src/core/org.freedesktop.systemd1.policy.in:54
@@ -60,7 +57,7 @@ msgid ""
 "Authentication is required to set or unset system and service manager "
 "environment variables."
 msgstr ""
-"È richiesto autenticarsi per configurare le variabili d'ambiente per la "
+"Autenticazione richiesta per configurare le variabili d'ambiente per la "
 "gestione dei servizi e del sistema."
 
 #: src/core/org.freedesktop.systemd1.policy.in:64
@@ -69,7 +66,7 @@ msgstr "Ricarica lo stato di systemd"
 
 #: src/core/org.freedesktop.systemd1.policy.in:65
 msgid "Authentication is required to reload the systemd state."
-msgstr "È richiesto autenticarsi per riavviare lo stato di sistemd."
+msgstr "Autenticazione richiesta per riavviare lo stato di sistemd."
 
 #: src/home/org.freedesktop.home1.policy:13
 msgid "Create a home area"
@@ -77,7 +74,7 @@ msgstr "Crea un'area home"
 
 #: src/home/org.freedesktop.home1.policy:14
 msgid "Authentication is required to create a user's home area."
-msgstr "È richiesto autenticarsi per creare l'area home di un utente."
+msgstr "Autenticazione richiesta per creare l'area home di un utente."
 
 #: src/home/org.freedesktop.home1.policy:23
 msgid "Remove a home area"
@@ -85,7 +82,7 @@ msgstr "Rimuovi un'area home"
 
 #: src/home/org.freedesktop.home1.policy:24
 msgid "Authentication is required to remove a user's home area."
-msgstr "È richiesto autenticarsi per rimuovere l'area home di un utente."
+msgstr "Autenticazione richiesta per rimuovere l'area home di un utente."
 
 #: src/home/org.freedesktop.home1.policy:33
 msgid "Check credentials of a home area"
@@ -95,7 +92,7 @@ msgstr "Controlla credenziali di un'area home"
 msgid ""
 "Authentication is required to check credentials against a user's home area."
 msgstr ""
-"È richiesto autenticarsi per controllare le credenziali di un'area home per "
+"Autenticazione richiesta per controllare le credenziali di un'area home per "
 "l'utente."
 
 #: src/home/org.freedesktop.home1.policy:43
@@ -104,7 +101,7 @@ msgstr "Aggiorna un'area home"
 
 #: src/home/org.freedesktop.home1.policy:44
 msgid "Authentication is required to update a user's home area."
-msgstr "È richiesto autenticarsi per aggiornare l'area home di un l'utente."
+msgstr "Autenticazione richiesta per aggiornare l'area home di un l'utente."
 
 #: src/home/org.freedesktop.home1.policy:53
 msgid "Resize a home area"
@@ -112,17 +109,16 @@ msgstr "Ridimensiona un'area home"
 
 #: src/home/org.freedesktop.home1.policy:54
 msgid "Authentication is required to resize a user's home area."
-msgstr "È richiesto autenticarsi per ridimensionare l'area home di un'utente."
+msgstr "Autenticazione richiesta per ridimensionare l'area home di un'utente."
 
 #: src/home/org.freedesktop.home1.policy:63
 msgid "Change password of a home area"
 msgstr "Modifica password di un'area home"
 
 #: src/home/org.freedesktop.home1.policy:64
-msgid ""
-"Authentication is required to change the password of a user's home area."
+msgid "Authentication is required to change the password of a user's home area."
 msgstr ""
-"È richiesto autenticarsi per modificare la password dell'area home di un "
+"Autenticazione richiesta per modificare la password dell'area home di un "
 "utente."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
@@ -131,7 +127,7 @@ msgstr "Configura il nome host"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
 msgid "Authentication is required to set the local hostname."
-msgstr "È richiesto autenticarsi per configurare il nome host locale."
+msgstr "Autenticazione richiesta per configurare il nome host locale."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
 msgid "Set static hostname"
@@ -142,7 +138,7 @@ msgid ""
 "Authentication is required to set the statically configured local hostname, "
 "as well as the pretty hostname."
 msgstr ""
-"È richiesto autenticarsi per configurare staticamente il nome host locale e "
+"Autenticazione richiesta per configurare staticamente il nome host locale e "
 "il nome host descrittivo."
 
 #: src/hostname/org.freedesktop.hostname1.policy:41
@@ -152,7 +148,7 @@ msgstr "Configura le informazioni sulla macchina"
 #: src/hostname/org.freedesktop.hostname1.policy:42
 msgid "Authentication is required to set local machine information."
 msgstr ""
-"È richiesto autenticarsi per configurare le informazioni sulla macchina "
+"Autenticazione richiesta per configurare le informazioni sulla macchina "
 "locale."
 
 #: src/hostname/org.freedesktop.hostname1.policy:51
@@ -161,7 +157,7 @@ msgstr "Ottieni UUID del prodotto"
 
 #: src/hostname/org.freedesktop.hostname1.policy:52
 msgid "Authentication is required to get product UUID."
-msgstr "È richiesto autenticarsi per ottenere lo UUID del prodotto."
+msgstr "Autenticazione richiesta per ottenere lo UUID del prodotto."
 
 #: src/import/org.freedesktop.import1.policy:22
 msgid "Import a VM or container image"
@@ -169,7 +165,7 @@ msgstr "Importa un'immagine VM o un container"
 
 #: src/import/org.freedesktop.import1.policy:23
 msgid "Authentication is required to import a VM or container image"
-msgstr "È richiesto autenticarsi per importare un'immagine VM o un container"
+msgstr "Autenticazione richiesta per importare un'immagine VM o un container"
 
 #: src/import/org.freedesktop.import1.policy:32
 msgid "Export a VM or container image"
@@ -177,7 +173,7 @@ msgstr "Esporta un'immagine VM o un container"
 
 #: src/import/org.freedesktop.import1.policy:33
 msgid "Authentication is required to export a VM or container image"
-msgstr "È richiesto autenticarsi per esportare un'immagine VM o un container"
+msgstr "Autenticazione richiesta per esportare un'immagine VM o un container"
 
 #: src/import/org.freedesktop.import1.policy:42
 msgid "Download a VM or container image"
@@ -185,7 +181,7 @@ msgstr "Scarica un'immagine VM o un container"
 
 #: src/import/org.freedesktop.import1.policy:43
 msgid "Authentication is required to download a VM or container image"
-msgstr "È richiesto autenticarsi per scaricare un'immagine VM o un container"
+msgstr "Autenticazione richiesta per scaricare un'immagine VM o un container"
 
 #: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
@@ -194,8 +190,7 @@ msgstr "Configura le impostazioni regionali di sistema"
 #: src/locale/org.freedesktop.locale1.policy:23
 msgid "Authentication is required to set the system locale."
 msgstr ""
-"È richiesto autenticarsi per configurare le impostazioni regionali di "
-"sistema."
+"Autenticazione richiesta per configurare le impostazioni regionali di sistema."
 
 #: src/locale/org.freedesktop.locale1.policy:33
 msgid "Set system keyboard settings"
@@ -203,7 +198,7 @@ msgstr "Configura la tastiera di sistema"
 
 #: src/locale/org.freedesktop.locale1.policy:34
 msgid "Authentication is required to set the system keyboard settings."
-msgstr "È richiesto autenticarsi per configurare la tastiera di sistema."
+msgstr "Autenticazione richiesta per configurare la tastiera di sistema."
 
 #: src/login/org.freedesktop.login1.policy:22
 msgid "Allow applications to inhibit system shutdown"
@@ -213,7 +208,7 @@ msgstr "Consenti alle applicazioni di inibire lo spegnimento del sistema"
 msgid ""
 "Authentication is required for an application to inhibit system shutdown."
 msgstr ""
-"È richiesto autenticarsi per un'applicazione per inibire lo spegnimento del "
+"Autenticazione richiesta per un'applicazione per inibire lo spegnimento del "
 "sistema."
 
 #: src/login/org.freedesktop.login1.policy:33
@@ -223,7 +218,7 @@ msgstr "Consenti alle applicazioni di ritardare lo spegnimento del sistema"
 #: src/login/org.freedesktop.login1.policy:34
 msgid "Authentication is required for an application to delay system shutdown."
 msgstr ""
-"È richiesto autenticarsi ad un'applicazione per ritardare lo spegnimento del "
+"Autenticazione richiesta ad un'applicazione per ritardare lo spegnimento del "
 "sistema."
 
 #: src/login/org.freedesktop.login1.policy:44
@@ -233,7 +228,7 @@ msgstr "Consenti alle applicazioni di inibire la pausa del sistema"
 #: src/login/org.freedesktop.login1.policy:45
 msgid "Authentication is required for an application to inhibit system sleep."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa inibire la pausa del "
+"Autenticazione richiesta affinché un'applicazione possa inibire la pausa del "
 "sistema."
 
 #: src/login/org.freedesktop.login1.policy:55
@@ -243,7 +238,7 @@ msgstr "Consenti alle applicazioni di ritardare la pausa del sistema"
 #: src/login/org.freedesktop.login1.policy:56
 msgid "Authentication is required for an application to delay system sleep."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa ritardare la pausa "
+"Autenticazione richiesta affinché un'applicazione possa ritardare la pausa "
 "del sistema."
 
 #: src/login/org.freedesktop.login1.policy:65
@@ -256,7 +251,7 @@ msgid ""
 "Authentication is required for an application to inhibit automatic system "
 "suspend."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa inibire la "
+"Autenticazione richiesta affinché un'applicazione possa inibire la "
 "sospensione automatica del sistema."
 
 #: src/login/org.freedesktop.login1.policy:75
@@ -270,7 +265,7 @@ msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the power key."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa inibire la gestione "
+"Autenticazione richiesta affinché un'applicazione possa inibire la gestione "
 "di sistema del tasto accensione."
 
 #: src/login/org.freedesktop.login1.policy:86
@@ -284,7 +279,7 @@ msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the suspend key."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa inibire la gestione "
+"Autenticazione richiesta affinché un'applicazione possa inibire la gestione "
 "di sistema del tasto di sospensione."
 
 #: src/login/org.freedesktop.login1.policy:97
@@ -298,7 +293,7 @@ msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the hibernate key."
 msgstr ""
-"È richiesto autenticarsi affinché un'applicazione possa inibire la gestione "
+"Autenticazione richiesta affinché un'applicazione possa inibire la gestione "
 "di sistema del tasto di ibernazione."
 
 #: src/login/org.freedesktop.login1.policy:107
@@ -312,7 +307,7 @@ msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the lid switch."
 msgstr ""
-"È richiesto autenticarsi per consentire a un'applicazione di inibire la "
+"Autenticazione richiesta per consentire a un'applicazione di inibire la "
 "gestione di sistema alla apertura/chiusura del portatile."
 
 #: src/login/org.freedesktop.login1.policy:117
@@ -332,7 +327,7 @@ msgstr "Consenti agli utenti non connessi di eseguire programmi"
 #: src/login/org.freedesktop.login1.policy:128
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
-"È richiesto autenticarsi per consentire agli utenti non connessi di eseguire "
+"Autenticazione richiesta per consentire agli utenti non connessi di eseguire "
 "programmi."
 
 #: src/login/org.freedesktop.login1.policy:137
@@ -342,7 +337,7 @@ msgstr "Consenti di collegare dispositivi alle postazioni"
 #: src/login/org.freedesktop.login1.policy:138
 msgid "Authentication is required to attach a device to a seat."
 msgstr ""
-"È richiesto autenticarsi per collegare un dispositivo ad una postazione."
+"Autenticazione richiesta per collegare un dispositivo ad una postazione."
 
 #: src/login/org.freedesktop.login1.policy:148
 msgid "Flush device to seat attachments"
@@ -351,7 +346,7 @@ msgstr "Scollega i dispositivi dalla postazione"
 #: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to reset how devices are attached to seats."
 msgstr ""
-"È richiesto autenticarsi per ripristinare come i dispositivi sono collegati "
+"Autenticazione richiesta per ripristinare come i dispositivi sono collegati "
 "alle postazioni."
 
 #: src/login/org.freedesktop.login1.policy:158
@@ -360,7 +355,7 @@ msgstr "Spegni il sistema"
 
 #: src/login/org.freedesktop.login1.policy:159
 msgid "Authentication is required to power off the system."
-msgstr "È richiesto autenticarsi per spegnere il sistema."
+msgstr "Autenticazione richiesta per spegnere il sistema."
 
 #: src/login/org.freedesktop.login1.policy:169
 msgid "Power off the system while other users are logged in"
@@ -371,7 +366,7 @@ msgid ""
 "Authentication is required to power off the system while other users are "
 "logged in."
 msgstr ""
-"È richiesto autenticarsi per spegnere il sistema mentre altri utenti sono "
+"Autenticazione richiesta per spegnere il sistema mentre altri utenti sono "
 "connessi."
 
 #: src/login/org.freedesktop.login1.policy:180
@@ -383,7 +378,7 @@ msgid ""
 "Authentication is required to power off the system while an application is "
 "inhibiting this."
 msgstr ""
-"È richiesto autenticarsi per spegnere il sistema mentre un'applicazione "
+"Autenticazione richiesta per spegnere il sistema mentre un'applicazione "
 "chiede di inibirne l'azione."
 
 #: src/login/org.freedesktop.login1.policy:191
@@ -392,7 +387,7 @@ msgstr "Riavvia il sistema"
 
 #: src/login/org.freedesktop.login1.policy:192
 msgid "Authentication is required to reboot the system."
-msgstr "È richiesto autenticarsi per riavviare il sistema."
+msgstr "Autenticazione richiesta per riavviare il sistema."
 
 #: src/login/org.freedesktop.login1.policy:202
 msgid "Reboot the system while other users are logged in"
@@ -403,7 +398,7 @@ msgid ""
 "Authentication is required to reboot the system while other users are logged "
 "in."
 msgstr ""
-"È richiesto autenticarsi per riavviare il sistema mentre altri utenti sono "
+"Autenticazione richiesta per riavviare il sistema mentre altri utenti sono "
 "connessi."
 
 #: src/login/org.freedesktop.login1.policy:213
@@ -415,7 +410,7 @@ msgid ""
 "Authentication is required to reboot the system while an application is "
 "inhibiting this."
 msgstr ""
-"È richiesto autenticarsi per riavviare il sistema mentre un'applicazione "
+"Autenticazione richiesta per riavviare il sistema mentre un'applicazione "
 "chiede di inibirne l'azione."
 
 #: src/login/org.freedesktop.login1.policy:224
@@ -424,7 +419,7 @@ msgstr "Ferma il sistema"
 
 #: src/login/org.freedesktop.login1.policy:225
 msgid "Authentication is required to halt the system."
-msgstr "È richiesto autenticarsi per fermare il sistema."
+msgstr "Autenticazione richiesta per fermare il sistema."
 
 #: src/login/org.freedesktop.login1.policy:235
 msgid "Halt the system while other users are logged in"
@@ -432,10 +427,9 @@ msgstr "Ferma il sistema mentre altri utenti sono connessi"
 
 #: src/login/org.freedesktop.login1.policy:236
 msgid ""
-"Authentication is required to halt the system while other users are logged "
-"in."
+"Authentication is required to halt the system while other users are logged in."
 msgstr ""
-"È richiesto autenticarsi per fermare il sistema mentre altri utenti sono "
+"Autenticazione richiesta per fermare il sistema mentre altri utenti sono "
 "connessi."
 
 #: src/login/org.freedesktop.login1.policy:246
@@ -447,7 +441,7 @@ msgid ""
 "Authentication is required to halt the system while an application is "
 "inhibiting this."
 msgstr ""
-"È richiesto autenticarsi per ibernare il sistema mentre un'applicazione ne "
+"Autenticazione richiesta per ibernare il sistema mentre un'applicazione ne "
 "inibisce l'azione."
 
 #: src/login/org.freedesktop.login1.policy:257
@@ -456,7 +450,7 @@ msgstr "Sospendi il sistema"
 
 #: src/login/org.freedesktop.login1.policy:258
 msgid "Authentication is required to suspend the system."
-msgstr "È richiesto autenticarsi per sospendere il sistema."
+msgstr "Autenticazione richiesta per sospendere il sistema."
 
 #: src/login/org.freedesktop.login1.policy:267
 msgid "Suspend the system while other users are logged in"
@@ -464,10 +458,10 @@ msgstr "Sospendi il sistema mentre altri utenti sono connessi"
 
 #: src/login/org.freedesktop.login1.policy:268
 msgid ""
-"Authentication is required to suspend the system while other users are "
-"logged in."
+"Authentication is required to suspend the system while other users are logged "
+"in."
 msgstr ""
-"È richiesto autenticarsi per sospendere il sistema mentre altri utenti sono "
+"Autenticazione richiesta per sospendere il sistema mentre altri utenti sono "
 "connessi."
 
 #: src/login/org.freedesktop.login1.policy:278
@@ -479,7 +473,7 @@ msgid ""
 "Authentication is required to suspend the system while an application is "
 "inhibiting this."
 msgstr ""
-"È richiesto autenticarsi per sospendere il sistema mentre un'applicazione "
+"Autenticazione richiesta per sospendere il sistema mentre un'applicazione "
 "chiede di inibirne l'azione."
 
 #: src/login/org.freedesktop.login1.policy:289
@@ -488,7 +482,7 @@ msgstr "Iberna il sistema"
 
 #: src/login/org.freedesktop.login1.policy:290
 msgid "Authentication is required to hibernate the system."
-msgstr "È richiesto autenticarsi per ibernare il sistema."
+msgstr "Autenticazione richiesta per ibernare il sistema."
 
 #: src/login/org.freedesktop.login1.policy:299
 msgid "Hibernate the system while other users are logged in"
@@ -499,7 +493,7 @@ msgid ""
 "Authentication is required to hibernate the system while other users are "
 "logged in."
 msgstr ""
-"È richiesto autenticarsi per ibernare il sistema mentre altri utenti sono "
+"Autenticazione richiesta per ibernare il sistema mentre altri utenti sono "
 "connessi."
 
 #: src/login/org.freedesktop.login1.policy:310
@@ -511,7 +505,7 @@ msgid ""
 "Authentication is required to hibernate the system while an application is "
 "inhibiting this."
 msgstr ""
-"È richiesto autenticarsi per ibernare il sistema mentre un'applicazione "
+"Autenticazione richiesta per ibernare il sistema mentre un'applicazione "
 "chiede di inibirne l'azione."
 
 #: src/login/org.freedesktop.login1.policy:321
@@ -521,7 +515,7 @@ msgstr "Gestione delle sessioni attive, utenti e postazioni"
 #: src/login/org.freedesktop.login1.policy:322
 msgid "Authentication is required to manage active sessions, users and seats."
 msgstr ""
-"È richiesto autenticarsi per gestire le sessioni attive, gli utenti e le "
+"Autenticazione richiesta per gestire le sessioni attive, gli utenti e le "
 "postazioni."
 
 #: src/login/org.freedesktop.login1.policy:331
@@ -530,7 +524,7 @@ msgstr "Blocca/sblocca sessioni attive"
 
 #: src/login/org.freedesktop.login1.policy:332
 msgid "Authentication is required to lock or unlock active sessions."
-msgstr "È richiesto autenticarsi per bloccare o sbloccare le sessioni attive."
+msgstr "Autenticazione richiesta per bloccare o sbloccare le sessioni attive."
 
 #: src/login/org.freedesktop.login1.policy:341
 msgid "Set the reboot \"reason\" in the kernel"
@@ -539,8 +533,7 @@ msgstr "Indica il \"motivo\" del riavvio nel kernel"
 #: src/login/org.freedesktop.login1.policy:342
 msgid "Authentication is required to set the reboot \"reason\" in the kernel."
 msgstr ""
-"È richiesto autenticarsi per configurare il \"motivo\" del riavvio nel "
-"kernel."
+"Autenticazione richiesta per configurare il \"motivo\" del riavvio nel kernel."
 
 #: src/login/org.freedesktop.login1.policy:352
 msgid "Indicate to the firmware to boot to setup interface"
@@ -551,7 +544,7 @@ msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
 msgstr ""
-"È richiesto autenticarsi per indicare al firmware l'avvio di un'interfaccia "
+"Autenticazione richiesta per indicare al firmware l'avvio di un'interfaccia "
 "di configurazione."
 
 #: src/login/org.freedesktop.login1.policy:363
@@ -560,11 +553,11 @@ msgstr "Indicate al boot loader di avviare un menu"
 
 #: src/login/org.freedesktop.login1.policy:364
 msgid ""
-"Authentication is required to indicate to the boot loader to boot to the "
-"boot loader menu."
+"Authentication is required to indicate to the boot loader to boot to the boot "
+"loader menu."
 msgstr ""
-"È richiesto autenticarsi per indicate al boot loader l'avvio di uno "
-"specifico menu."
+"Autenticazione richiesta per indicate al boot loader l'avvio di uno specifico "
+"menu."
 
 #: src/login/org.freedesktop.login1.policy:374
 msgid "Indicate to the boot loader to boot a specific entry"
@@ -575,8 +568,8 @@ msgid ""
 "Authentication is required to indicate to the boot loader to boot into a "
 "specific boot loader entry."
 msgstr ""
-"È richiesto autenticarsi per indicare al boot loader l'avvio di una "
-"specifica voce in elenco."
+"Autenticazione richiesta per indicare al boot loader l'avvio di una specifica "
+"voce in elenco."
 
 #: src/login/org.freedesktop.login1.policy:385
 msgid "Set a wall message"
@@ -584,7 +577,7 @@ msgstr "Configura un messaggio per gli utenti"
 
 #: src/login/org.freedesktop.login1.policy:386
 msgid "Authentication is required to set a wall message"
-msgstr "È richiesto autenticarsi per configurare un messaggio per gli utenti"
+msgstr "Autenticazione richiesta per configurare un messaggio per gli utenti"
 
 #: src/login/org.freedesktop.login1.policy:395
 msgid "Change Session"
@@ -592,7 +585,7 @@ msgstr "Cambia sessione"
 
 #: src/login/org.freedesktop.login1.policy:396
 msgid "Authentication is required to change the virtual terminal."
-msgstr "È richiesto autenticarsi per cambiare il terminale virtuale."
+msgstr "Autenticazione richiesta per cambiare il terminale virtuale."
 
 #: src/machine/org.freedesktop.machine1.policy:22
 msgid "Log into a local container"
@@ -600,7 +593,7 @@ msgstr "Accedi ad un container locale"
 
 #: src/machine/org.freedesktop.machine1.policy:23
 msgid "Authentication is required to log into a local container."
-msgstr "È richiesto autenticarsi per accedere ad un container locale."
+msgstr "Autenticazione richiesta per accedere ad un container locale."
 
 #: src/machine/org.freedesktop.machine1.policy:32
 msgid "Log into the local host"
@@ -608,7 +601,7 @@ msgstr "Accedi in un host locale"
 
 #: src/machine/org.freedesktop.machine1.policy:33
 msgid "Authentication is required to log into the local host."
-msgstr "È richiesto autenticarsi per accedere ad un host locale."
+msgstr "Autenticazione richiesta per accedere ad un host locale."
 
 #: src/machine/org.freedesktop.machine1.policy:42
 msgid "Acquire a shell in a local container"
@@ -616,7 +609,7 @@ msgstr "Apri una shell in un container locale"
 
 #: src/machine/org.freedesktop.machine1.policy:43
 msgid "Authentication is required to acquire a shell in a local container."
-msgstr "È richiesto autenticarsi per aprire una shell in un container locale."
+msgstr "Autenticazione richiesta per aprire una shell in un container locale."
 
 #: src/machine/org.freedesktop.machine1.policy:53
 msgid "Acquire a shell on the local host"
@@ -624,17 +617,16 @@ msgstr "Apri una shell in un host locale"
 
 #: src/machine/org.freedesktop.machine1.policy:54
 msgid "Authentication is required to acquire a shell on the local host."
-msgstr "È richiesto autenticarsi per aprire una shell in un host locale."
+msgstr "Autenticazione richiesta per aprire una shell in un host locale."
 
 #: src/machine/org.freedesktop.machine1.policy:64
 msgid "Acquire a pseudo TTY in a local container"
 msgstr "Apri un pseudo TTY in un container locale"
 
 #: src/machine/org.freedesktop.machine1.policy:65
-msgid ""
-"Authentication is required to acquire a pseudo TTY in a local container."
+msgid "Authentication is required to acquire a pseudo TTY in a local container."
 msgstr ""
-"È richiesto autenticarsi per aprire un pseudo TTY in un container locale."
+"Autenticazione richiesta per aprire un pseudo TTY in un container locale."
 
 #: src/machine/org.freedesktop.machine1.policy:74
 msgid "Acquire a pseudo TTY on the local host"
@@ -642,7 +634,7 @@ msgstr "Apri un pseudo TTY in un host locale"
 
 #: src/machine/org.freedesktop.machine1.policy:75
 msgid "Authentication is required to acquire a pseudo TTY on the local host."
-msgstr "È richiesto autenticarsi per aprire un pseudo TTY in un host locale."
+msgstr "Autenticazione richiesta per aprire un pseudo TTY in un host locale."
 
 #: src/machine/org.freedesktop.machine1.policy:84
 msgid "Manage local virtual machines and containers"
@@ -652,7 +644,7 @@ msgstr "Gestisci le virtual machine e i container locali"
 msgid ""
 "Authentication is required to manage local virtual machines and containers."
 msgstr ""
-"È richiesto autenticarsi per gestire le virtual machine e i container locali."
+"Autenticazione richiesta per gestire le virtual machine e i container locali."
 
 #: src/machine/org.freedesktop.machine1.policy:95
 msgid "Manage local virtual machine and container images"
@@ -663,7 +655,7 @@ msgid ""
 "Authentication is required to manage local virtual machine and container "
 "images."
 msgstr ""
-"È richiesto autenticarsi per gestire le immagini delle virtual machine e dei "
+"Autenticazione richiesta per gestire le immagini delle virtual machine e dei "
 "container locali."
 
 #: src/network/org.freedesktop.network1.policy:22
@@ -672,7 +664,7 @@ msgstr "Configura server NTP"
 
 #: src/network/org.freedesktop.network1.policy:23
 msgid "Authentication is required to set NTP servers."
-msgstr "È richiesto autenticarsi per configurare i server NTP."
+msgstr "Autenticazione richiesta per configurare i server NTP."
 
 #: src/network/org.freedesktop.network1.policy:33
 #: src/resolve/org.freedesktop.resolve1.policy:44
@@ -682,7 +674,7 @@ msgstr "Configura i server DNS"
 #: src/network/org.freedesktop.network1.policy:34
 #: src/resolve/org.freedesktop.resolve1.policy:45
 msgid "Authentication is required to set DNS servers."
-msgstr "È richiesto autenticarsi per configurare i server DNS."
+msgstr "Autenticazione richiesta per configurare i server DNS."
 
 #: src/network/org.freedesktop.network1.policy:44
 #: src/resolve/org.freedesktop.resolve1.policy:55
@@ -692,7 +684,7 @@ msgstr "Configura domini"
 #: src/network/org.freedesktop.network1.policy:45
 #: src/resolve/org.freedesktop.resolve1.policy:56
 msgid "Authentication is required to set domains."
-msgstr "È richiesto autenticarsi per configurare i domini."
+msgstr "Autenticazione richiesta per configurare i domini."
 
 #: src/network/org.freedesktop.network1.policy:55
 #: src/resolve/org.freedesktop.resolve1.policy:66
@@ -703,7 +695,7 @@ msgstr "Configura la tabella di instradamento"
 #: src/resolve/org.freedesktop.resolve1.policy:67
 msgid "Authentication is required to set default route."
 msgstr ""
-"È richiesto autenticarsi per configurare la tabella di instradamento "
+"Autenticazione richiesta per configurare la tabella di instradamento "
 "predefinita."
 
 #: src/network/org.freedesktop.network1.policy:66
@@ -714,7 +706,7 @@ msgstr "Abilita/disabilita LLMNR"
 #: src/network/org.freedesktop.network1.policy:67
 #: src/resolve/org.freedesktop.resolve1.policy:78
 msgid "Authentication is required to enable or disable LLMNR."
-msgstr "È richiesto autenticarsi per attivare/disattivare LLMNR."
+msgstr "Autenticazione richiesta per attivare/disattivare LLMNR."
 
 #: src/network/org.freedesktop.network1.policy:77
 #: src/resolve/org.freedesktop.resolve1.policy:88
@@ -724,7 +716,7 @@ msgstr "Abilita/disabilita DNS multicast"
 #: src/network/org.freedesktop.network1.policy:78
 #: src/resolve/org.freedesktop.resolve1.policy:89
 msgid "Authentication is required to enable or disable multicast DNS."
-msgstr "È richiesto autenticarsi per abilitare/disabilitare DNS multicast."
+msgstr "Autenticazione richiesta per abilitare/disabilitare DNS multicast."
 
 #: src/network/org.freedesktop.network1.policy:88
 #: src/resolve/org.freedesktop.resolve1.policy:99
@@ -734,7 +726,7 @@ msgstr "Abilita/disabilita DNS su TLS"
 #: src/network/org.freedesktop.network1.policy:89
 #: src/resolve/org.freedesktop.resolve1.policy:100
 msgid "Authentication is required to enable or disable DNS over TLS."
-msgstr "È richiesto autenticarsi per abilitare o disabilitare DNS su TLS."
+msgstr "Autenticazione richiesta per abilitare o disabilitare DNS su TLS."
 
 #: src/network/org.freedesktop.network1.policy:99
 #: src/resolve/org.freedesktop.resolve1.policy:110
@@ -744,7 +736,7 @@ msgstr "Abilita/disabilita DNSSEC"
 #: src/network/org.freedesktop.network1.policy:100
 #: src/resolve/org.freedesktop.resolve1.policy:111
 msgid "Authentication is required to enable or disable DNSSEC."
-msgstr "È richiesto autenticarsi per abilitare o disabilitare DNSSEC."
+msgstr "Autenticazione richiesta per abilitare o disabilitare DNSSEC."
 
 #: src/network/org.freedesktop.network1.policy:110
 #: src/resolve/org.freedesktop.resolve1.policy:121
@@ -754,7 +746,7 @@ msgstr "Configura DNSSEC Negative Trust Anchors"
 #: src/network/org.freedesktop.network1.policy:111
 #: src/resolve/org.freedesktop.resolve1.policy:122
 msgid "Authentication is required to set DNSSEC Negative Trust Anchors."
-msgstr "È richiesto autenticarsi per configurare DNSSEC Negative Trust Anchors."
+msgstr "Autenticazione richiesta per configurare DNSSEC Negative Trust Anchors."
 
 #: src/network/org.freedesktop.network1.policy:121
 msgid "Revert NTP settings"
@@ -762,7 +754,7 @@ msgstr "Ripristina configurazioni NTP"
 
 #: src/network/org.freedesktop.network1.policy:122
 msgid "Authentication is required to reset NTP settings."
-msgstr "È richiesto autenticarsi per ripristinare le configurazioni NTP."
+msgstr "Autenticazione richiesta per ripristinare le configurazioni NTP."
 
 #: src/network/org.freedesktop.network1.policy:132
 msgid "Revert DNS settings"
@@ -770,7 +762,7 @@ msgstr "Ripristina configurazioni DNS"
 
 #: src/network/org.freedesktop.network1.policy:133
 msgid "Authentication is required to reset DNS settings."
-msgstr "È richiesto autenticarsi per ripristinare le configurazioni DNS."
+msgstr "Autenticazione richiesta per ripristinare le configurazioni DNS."
 
 #: src/network/org.freedesktop.network1.policy:143
 msgid "DHCP server sends force renew message"
@@ -778,7 +770,7 @@ msgstr "Il server DHCP invia messaggi di rinnovo forzato"
 
 #: src/network/org.freedesktop.network1.policy:144
 msgid "Authentication is required to send force renew message."
-msgstr "È richiesto autenticarsi per inviare messaggi di rinnovo forzato."
+msgstr "Autenticazione richiesta per inviare messaggi di rinnovo forzato."
 
 #: src/network/org.freedesktop.network1.policy:154
 msgid "Renew dynamic addresses"
@@ -786,7 +778,7 @@ msgstr "Rinnova indirizzi dinamici"
 
 #: src/network/org.freedesktop.network1.policy:155
 msgid "Authentication is required to renew dynamic addresses."
-msgstr "È richiesto autenticarsi per rinnovare gli indirizzi dinamici."
+msgstr "Autenticazione richiesta per rinnovare gli indirizzi dinamici."
 
 #: src/network/org.freedesktop.network1.policy:165
 msgid "Reload network settings"
@@ -794,7 +786,7 @@ msgstr "Ricarica configurazioni di rete"
 
 #: src/network/org.freedesktop.network1.policy:166
 msgid "Authentication is required to reload network settings."
-msgstr "È richiesto autenticarsi per ricaricare le configurazioni di rete."
+msgstr "Autenticazione richiesta per ricaricare le configurazioni di rete."
 
 #: src/network/org.freedesktop.network1.policy:176
 msgid "Reconfigure network interface"
@@ -802,7 +794,7 @@ msgstr "Riconfigura interfaccia di rete"
 
 #: src/network/org.freedesktop.network1.policy:177
 msgid "Authentication is required to reconfigure network interface."
-msgstr "È richiesto autenticarsi per riconfigurare l'interfaccia di rete."
+msgstr "Autenticazione richiesta per riconfigurare l'interfaccia di rete."
 
 #: src/portable/org.freedesktop.portable1.policy:13
 msgid "Inspect a portable service image"
@@ -811,17 +803,16 @@ msgstr "Ispeziona un'immagine di servizio portabile"
 #: src/portable/org.freedesktop.portable1.policy:14
 msgid "Authentication is required to inspect a portable service image."
 msgstr ""
-"È richiesto autenticarsi per ispezionare un'immagine di servizio portabile."
+"Autenticazione richiesta per ispezionare un'immagine di servizio portabile."
 
 #: src/portable/org.freedesktop.portable1.policy:23
 msgid "Attach or detach a portable service image"
 msgstr "Collega o meno un'immagine di servizio portabile"
 
 #: src/portable/org.freedesktop.portable1.policy:24
-msgid ""
-"Authentication is required to attach or detach a portable service image."
+msgid "Authentication is required to attach or detach a portable service image."
 msgstr ""
-"È richiesto autenticarsi per collegare o meno un'immagine di servizio "
+"Autenticazione richiesta per collegare o meno un'immagine di servizio "
 "portabile."
 
 #: src/portable/org.freedesktop.portable1.policy:34
@@ -829,10 +820,9 @@ msgid "Delete or modify portable service image"
 msgstr "Elimina o modifica un'immagine di servizio portabile"
 
 #: src/portable/org.freedesktop.portable1.policy:35
-msgid ""
-"Authentication is required to delete or modify a portable service image."
+msgid "Authentication is required to delete or modify a portable service image."
 msgstr ""
-"È richiesto autenticarsi per eliminare o modificare un'immagine di servizio "
+"Autenticazione richiesta per eliminare o modificare un'immagine di servizio "
 "portabile."
 
 #: src/resolve/org.freedesktop.resolve1.policy:22
@@ -841,7 +831,7 @@ msgstr "Registra un servizio DNS-SD"
 
 #: src/resolve/org.freedesktop.resolve1.policy:23
 msgid "Authentication is required to register a DNS-SD service"
-msgstr "È richiesto autenticarsi per registrare un servizio DNS-SD"
+msgstr "Autenticazione richiesta per registrare un servizio DNS-SD"
 
 #: src/resolve/org.freedesktop.resolve1.policy:33
 msgid "Unregister a DNS-SD service"
@@ -850,7 +840,7 @@ msgstr "Annulla la registrazione di un servizio DNS-SD"
 #: src/resolve/org.freedesktop.resolve1.policy:34
 msgid "Authentication is required to unregister a DNS-SD service"
 msgstr ""
-"È richiesto autenticarsi per annullare la registrazione di un servizio DNS-SD"
+"Autenticazione richiesta per annullare la registrazione di un servizio DNS-SD"
 
 #: src/resolve/org.freedesktop.resolve1.policy:132
 msgid "Revert name resolution settings"
@@ -859,7 +849,7 @@ msgstr "Ripristina le configurazioni per la risoluzione dei nomi"
 #: src/resolve/org.freedesktop.resolve1.policy:133
 msgid "Authentication is required to reset name resolution settings."
 msgstr ""
-"È richiesto autenticarsi per ripristinare le configurazioni per la "
+"Autenticazione richiesta per ripristinare le configurazioni per la "
 "risoluzione dei nomi."
 
 #: src/timedate/org.freedesktop.timedate1.policy:22
@@ -868,7 +858,7 @@ msgstr "Imposta l'orario di sistema"
 
 #: src/timedate/org.freedesktop.timedate1.policy:23
 msgid "Authentication is required to set the system time."
-msgstr "È richiesto autenticarsi per impostare l'orario di sistema."
+msgstr "Autenticazione richiesta per impostare l'orario di sistema."
 
 #: src/timedate/org.freedesktop.timedate1.policy:33
 msgid "Set system timezone"
@@ -876,7 +866,7 @@ msgstr "Imposta il fuso orario di sistema"
 
 #: src/timedate/org.freedesktop.timedate1.policy:34
 msgid "Authentication is required to set the system timezone."
-msgstr "È richiesto autenticarsi per impostare il fuso orario di sistema."
+msgstr "Autenticazione richiesta per impostare il fuso orario di sistema."
 
 #: src/timedate/org.freedesktop.timedate1.policy:43
 msgid "Set RTC to local timezone or UTC"
@@ -886,10 +876,10 @@ msgstr ""
 
 #: src/timedate/org.freedesktop.timedate1.policy:44
 msgid ""
-"Authentication is required to control whether the RTC stores the local or "
-"UTC time."
+"Authentication is required to control whether the RTC stores the local or UTC "
+"time."
 msgstr ""
-"È richiesto autenticarsi per verificare se l'orologio di sistema (RTC) è "
+"Autenticazione richiesta per verificare se l'orologio di sistema (RTC) è "
 "configurato all'orario locale o al tempo civile (UTC)."
 
 #: src/timedate/org.freedesktop.timedate1.policy:53
@@ -901,53 +891,52 @@ msgid ""
 "Authentication is required to control whether network time synchronization "
 "shall be enabled."
 msgstr ""
-"È richiesto autenticarsi per verificare se la sincronizzazione dell'orario "
-"in rete deve essere attivata."
+"Autenticazione richiesta per verificare se la sincronizzazione dell'orario in "
+"rete deve essere attivata."
 
 #: src/core/dbus-unit.c:362
 msgid "Authentication is required to start '$(unit)'."
-msgstr "È richiesto autenticarsi per avviare «${unit}»."
+msgstr "Autenticazione richiesta per avviare '${unit}'."
 
 #: src/core/dbus-unit.c:363
 msgid "Authentication is required to stop '$(unit)'."
-msgstr "È richiesto autenticarsi per fermare «${unit}»."
+msgstr "Autenticazione richiesta per fermare '${unit}'."
 
 #: src/core/dbus-unit.c:364
 msgid "Authentication is required to reload '$(unit)'."
-msgstr "È richiesto autenticarsi per ricaricare «${unit}»."
+msgstr "Autenticazione richiesta per ricaricare '${unit}'."
 
 #: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366
 msgid "Authentication is required to restart '$(unit)'."
-msgstr "È richiesto autenticarsi per riavviare «${unit}»."
+msgstr "Autenticazione richiesta per riavviare '${unit}'."
 
 #: src/core/dbus-unit.c:538
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
 msgstr ""
-"È richiesto autenticarsi per inviare un segnale UNIX ai processi di "
-"«${unit}»."
+"Autenticazione richiesta per inviare un segnale UNIX ai processi di '${unit}'."
 
 #: src/core/dbus-unit.c:569
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
-"È richiesto autenticarsi per riconfigurare lo stato \"fallito\" di «${unit}»."
+"Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '${unit}'."
 
 #: src/core/dbus-unit.c:602
 msgid "Authentication is required to set properties on '$(unit)'."
-msgstr "È richiesto autenticarsi per configurare le proprietà di «${unit}»."
+msgstr "Autenticazione richiesta per configurare le proprietà di '${unit}'."
 
 #: src/core/dbus-unit.c:711
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
 msgstr ""
-"È richiesto autenticarsi per eliminare i file e le directory associate a "
-"«${unit}»."
+"Autenticazione richiesta per eliminare i file e le directory associate a "
+"'${unit}'."
 
 #: src/core/dbus-unit.c:760
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
 msgstr ""
-"È richiesto autenticarsi per bloccare/sbloccare il processo dell'unità "
-"«$(unit)»."
+"Autenticazione richiesta per bloccare/sbloccare il processo dell'unità "
+"'$(unit)'."
index 37c8ca7e395547b5d3efd5c9ca0237027df1494b..3bf4d092d941c3c2813ea717af011e54ed120c6c 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,8 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-08-19 18:02+0200\n"
-"PO-Revision-Date: 2020-05-03 13:50+0200\n"
+"POT-Creation-Date: 2020-09-10 03:33+0000\n"
+"PO-Revision-Date: 2020-10-18 13:10+0200\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
 "Language: pl\n"
@@ -309,57 +309,71 @@ msgstr ""
 "przez system."
 
 #: src/login/org.freedesktop.login1.policy:117
+msgid "Allow applications to inhibit system handling of the reboot key"
+msgstr ""
+"Zezwolenie programom na wstrzymanie obsługi klawisza ponownego uruchomienia "
+"przez system"
+
+#: src/login/org.freedesktop.login1.policy:118
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the reboot key."
+msgstr ""
+"Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza ponownego "
+"uruchomienia przez system."
+
+#: src/login/org.freedesktop.login1.policy:128
 msgid "Allow non-logged-in user to run programs"
 msgstr "Zezwolenie niezalogowanemu użytkownikowi na uruchamianie programów"
 
-#: src/login/org.freedesktop.login1.policy:118
+#: src/login/org.freedesktop.login1.policy:129
 msgid "Explicit request is required to run programs as a non-logged-in user."
 msgstr ""
 "Wymagane jest bezpośrednie żądanie, aby uruchamiać programy jako "
 "niezalogowany użytkownik."
 
-#: src/login/org.freedesktop.login1.policy:127
+#: src/login/org.freedesktop.login1.policy:138
 msgid "Allow non-logged-in users to run programs"
 msgstr "Zezwolenie niezalogowanym użytkownikom na uruchamianie programów"
 
-#: src/login/org.freedesktop.login1.policy:128
+#: src/login/org.freedesktop.login1.policy:139
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby uruchamiać programy jako niezalogowany "
 "użytkownik."
 
-#: src/login/org.freedesktop.login1.policy:137
+#: src/login/org.freedesktop.login1.policy:148
 msgid "Allow attaching devices to seats"
 msgstr "Zezwolenie na podłączanie urządzeń do stanowisk"
 
-#: src/login/org.freedesktop.login1.policy:138
+#: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to attach a device to a seat."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby podłączyć urządzenie do stanowiska."
 
-#: src/login/org.freedesktop.login1.policy:148
+#: src/login/org.freedesktop.login1.policy:159
 msgid "Flush device to seat attachments"
 msgstr "Usunięcie podłączenia urządzeń do stanowisk"
 
-#: src/login/org.freedesktop.login1.policy:149
+#: src/login/org.freedesktop.login1.policy:160
 msgid "Authentication is required to reset how devices are attached to seats."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie ustawić sposób podłączenia "
 "urządzeń do stanowisk."
 
-#: src/login/org.freedesktop.login1.policy:158
+#: src/login/org.freedesktop.login1.policy:169
 msgid "Power off the system"
 msgstr "Wyłączenie systemu"
 
-#: src/login/org.freedesktop.login1.policy:159
+#: src/login/org.freedesktop.login1.policy:170
 msgid "Authentication is required to power off the system."
 msgstr "Wymagane jest uwierzytelnienie, aby wyłączyć system."
 
-#: src/login/org.freedesktop.login1.policy:169
+#: src/login/org.freedesktop.login1.policy:180
 msgid "Power off the system while other users are logged in"
 msgstr "Wyłączenie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: src/login/org.freedesktop.login1.policy:170
+#: src/login/org.freedesktop.login1.policy:181
 msgid ""
 "Authentication is required to power off the system while other users are "
 "logged in."
@@ -367,11 +381,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy są zalogowani "
 "inni użytkownicy."
 
-#: src/login/org.freedesktop.login1.policy:180
+#: src/login/org.freedesktop.login1.policy:191
 msgid "Power off the system while an application is inhibiting this"
 msgstr "Wyłączenie systemu, kiedy program je wstrzymuje"
 
-#: src/login/org.freedesktop.login1.policy:181
+#: src/login/org.freedesktop.login1.policy:192
 msgid ""
 "Authentication is required to power off the system while an application is "
 "inhibiting this."
@@ -379,19 +393,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy program to "
 "wstrzymuje."
 
-#: src/login/org.freedesktop.login1.policy:191
+#: src/login/org.freedesktop.login1.policy:202
 msgid "Reboot the system"
 msgstr "Ponowne uruchomienie systemu"
 
-#: src/login/org.freedesktop.login1.policy:192
+#: src/login/org.freedesktop.login1.policy:203
 msgid "Authentication is required to reboot the system."
 msgstr "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system."
 
-#: src/login/org.freedesktop.login1.policy:202
+#: src/login/org.freedesktop.login1.policy:213
 msgid "Reboot the system while other users are logged in"
 msgstr "Ponowne uruchomienie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: src/login/org.freedesktop.login1.policy:203
+#: src/login/org.freedesktop.login1.policy:214
 msgid ""
 "Authentication is required to reboot the system while other users are logged "
 "in."
@@ -399,11 +413,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy są "
 "zalogowani inni użytkownicy."
 
-#: src/login/org.freedesktop.login1.policy:213
+#: src/login/org.freedesktop.login1.policy:224
 msgid "Reboot the system while an application is inhibiting this"
 msgstr "Ponowne uruchomienie systemu, kiedy program je wstrzymuje"
 
-#: src/login/org.freedesktop.login1.policy:214
+#: src/login/org.freedesktop.login1.policy:225
 msgid ""
 "Authentication is required to reboot the system while an application is "
 "inhibiting this."
@@ -411,19 +425,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy program "
 "to wstrzymuje."
 
-#: src/login/org.freedesktop.login1.policy:224
+#: src/login/org.freedesktop.login1.policy:235
 msgid "Halt the system"
 msgstr "Zatrzymanie systemu"
 
-#: src/login/org.freedesktop.login1.policy:225
+#: src/login/org.freedesktop.login1.policy:236
 msgid "Authentication is required to halt the system."
 msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać system."
 
-#: src/login/org.freedesktop.login1.policy:235
+#: src/login/org.freedesktop.login1.policy:246
 msgid "Halt the system while other users are logged in"
 msgstr "Zatrzymanie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: src/login/org.freedesktop.login1.policy:236
+#: src/login/org.freedesktop.login1.policy:247
 msgid ""
 "Authentication is required to halt the system while other users are logged "
 "in."
@@ -431,11 +445,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zatrzymać system, kiedy są zalogowani "
 "inni użytkownicy."
 
-#: src/login/org.freedesktop.login1.policy:246
+#: src/login/org.freedesktop.login1.policy:257
 msgid "Halt the system while an application is inhibiting this"
 msgstr "Zatrzymanie systemu, kiedy program je wstrzymuje"
 
-#: src/login/org.freedesktop.login1.policy:247
+#: src/login/org.freedesktop.login1.policy:258
 msgid ""
 "Authentication is required to halt the system while an application is "
 "inhibiting this."
@@ -443,19 +457,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zatrzymać system, kiedy program to "
 "wstrzymuje."
 
-#: src/login/org.freedesktop.login1.policy:257
+#: src/login/org.freedesktop.login1.policy:268
 msgid "Suspend the system"
 msgstr "Uśpienie systemu"
 
-#: src/login/org.freedesktop.login1.policy:258
+#: src/login/org.freedesktop.login1.policy:269
 msgid "Authentication is required to suspend the system."
 msgstr "Wymagane jest uwierzytelnienie, aby uśpić system."
 
-#: src/login/org.freedesktop.login1.policy:267
+#: src/login/org.freedesktop.login1.policy:278
 msgid "Suspend the system while other users are logged in"
 msgstr "Uśpienie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: src/login/org.freedesktop.login1.policy:268
+#: src/login/org.freedesktop.login1.policy:279
 msgid ""
 "Authentication is required to suspend the system while other users are "
 "logged in."
@@ -463,11 +477,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby uśpić system, kiedy są zalogowani inni "
 "użytkownicy."
 
-#: src/login/org.freedesktop.login1.policy:278
+#: src/login/org.freedesktop.login1.policy:289
 msgid "Suspend the system while an application is inhibiting this"
 msgstr "Uśpienie systemu, kiedy program je wstrzymuje"
 
-#: src/login/org.freedesktop.login1.policy:279
+#: src/login/org.freedesktop.login1.policy:290
 msgid ""
 "Authentication is required to suspend the system while an application is "
 "inhibiting this."
@@ -475,19 +489,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby uśpić system, kiedy program to "
 "wstrzymuje."
 
-#: src/login/org.freedesktop.login1.policy:289
+#: src/login/org.freedesktop.login1.policy:300
 msgid "Hibernate the system"
 msgstr "Hibernacja systemu"
 
-#: src/login/org.freedesktop.login1.policy:290
+#: src/login/org.freedesktop.login1.policy:301
 msgid "Authentication is required to hibernate the system."
 msgstr "Wymagane jest uwierzytelnienie, aby zahibernować system."
 
-#: src/login/org.freedesktop.login1.policy:299
+#: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while other users are logged in"
 msgstr "Hibernacja systemu, kiedy są zalogowani inni użytkownicy"
 
-#: src/login/org.freedesktop.login1.policy:300
+#: src/login/org.freedesktop.login1.policy:311
 msgid ""
 "Authentication is required to hibernate the system while other users are "
 "logged in."
@@ -495,11 +509,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy są zalogowani "
 "inni użytkownicy."
 
-#: src/login/org.freedesktop.login1.policy:310
+#: src/login/org.freedesktop.login1.policy:321
 msgid "Hibernate the system while an application is inhibiting this"
 msgstr "Hibernacja systemu, kiedy program ją wstrzymuje"
 
-#: src/login/org.freedesktop.login1.policy:311
+#: src/login/org.freedesktop.login1.policy:322
 msgid ""
 "Authentication is required to hibernate the system while an application is "
 "inhibiting this."
@@ -507,40 +521,40 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program to "
 "wstrzymuje."
 
-#: src/login/org.freedesktop.login1.policy:321
+#: src/login/org.freedesktop.login1.policy:332
 msgid "Manage active sessions, users and seats"
 msgstr "Zarządzanie aktywnymi sesjami, użytkownikami i stanowiskami"
 
-#: src/login/org.freedesktop.login1.policy:322
+#: src/login/org.freedesktop.login1.policy:333
 msgid "Authentication is required to manage active sessions, users and seats."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby zarządzać aktywnymi sesjami, "
 "użytkownikami i stanowiskami."
 
-#: src/login/org.freedesktop.login1.policy:331
+#: src/login/org.freedesktop.login1.policy:342
 msgid "Lock or unlock active sessions"
 msgstr "Zablokowanie lub odblokowanie aktywnych sesji"
 
-#: src/login/org.freedesktop.login1.policy:332
+#: src/login/org.freedesktop.login1.policy:343
 msgid "Authentication is required to lock or unlock active sessions."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby zablokować lub odblokować aktywne sesje."
 
-#: src/login/org.freedesktop.login1.policy:341
+#: src/login/org.freedesktop.login1.policy:352
 msgid "Set the reboot \"reason\" in the kernel"
 msgstr "Ustawienie przyczyny ponownego uruchomienia w jądrze"
 
-#: src/login/org.freedesktop.login1.policy:342
+#: src/login/org.freedesktop.login1.policy:353
 msgid "Authentication is required to set the reboot \"reason\" in the kernel."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić przyczynę ponownego uruchomienia "
 "w jądrze."
 
-#: src/login/org.freedesktop.login1.policy:352
+#: src/login/org.freedesktop.login1.policy:363
 msgid "Indicate to the firmware to boot to setup interface"
 msgstr "Wskazanie oprogramowaniu sprzętowemu, aby uruchomić interfejs ustawień"
 
-#: src/login/org.freedesktop.login1.policy:353
+#: src/login/org.freedesktop.login1.policy:364
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
@@ -548,11 +562,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wskazać oprogramowaniu sprzętowemu, że "
 "należy uruchomić interfejs ustawień."
 
-#: src/login/org.freedesktop.login1.policy:363
+#: src/login/org.freedesktop.login1.policy:374
 msgid "Indicate to the boot loader to boot to the boot loader menu"
 msgstr "Wskazanie programowi startowemu, aby uruchomić jego menu"
 
-#: src/login/org.freedesktop.login1.policy:364
+#: src/login/org.freedesktop.login1.policy:375
 msgid ""
 "Authentication is required to indicate to the boot loader to boot to the "
 "boot loader menu."
@@ -560,11 +574,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wskazać programowi startowemu, że należy "
 "uruchomić jego menu."
 
-#: src/login/org.freedesktop.login1.policy:374
+#: src/login/org.freedesktop.login1.policy:385
 msgid "Indicate to the boot loader to boot a specific entry"
 msgstr "Wskazanie programowi startowemu, aby uruchomić podany wpis"
 
-#: src/login/org.freedesktop.login1.policy:375
+#: src/login/org.freedesktop.login1.policy:386
 msgid ""
 "Authentication is required to indicate to the boot loader to boot into a "
 "specific boot loader entry."
@@ -572,19 +586,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wskazać programowi startowemu, że należy "
 "uruchomić podany wpis."
 
-#: src/login/org.freedesktop.login1.policy:385
+#: src/login/org.freedesktop.login1.policy:396
 msgid "Set a wall message"
 msgstr "Ustawienie komunikatu wall"
 
-#: src/login/org.freedesktop.login1.policy:386
+#: src/login/org.freedesktop.login1.policy:397
 msgid "Authentication is required to set a wall message"
 msgstr "Wymagane jest uwierzytelnienie, aby ustawić komunikat wall"
 
-#: src/login/org.freedesktop.login1.policy:395
+#: src/login/org.freedesktop.login1.policy:406
 msgid "Change Session"
 msgstr "Zmiana sesji"
 
-#: src/login/org.freedesktop.login1.policy:396
+#: src/login/org.freedesktop.login1.policy:407
 msgid "Authentication is required to change the virtual terminal."
 msgstr "Wymagane jest uwierzytelnienie, aby zmienić terminal wirtualny."
 
@@ -905,25 +919,25 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
 "czasu przez sieć."
 
-#: src/core/dbus-unit.c:362
+#: src/core/dbus-unit.c:359
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:363
+#: src/core/dbus-unit.c:360
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:364
+#: src/core/dbus-unit.c:361
 msgid "Authentication is required to reload '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366
+#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363
 msgid "Authentication is required to restart '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:538
+#: src/core/dbus-unit.c:535
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
@@ -931,18 +945,18 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wysłać sygnał uniksowy do procesów "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:569
+#: src/core/dbus-unit.c:566
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:602
+#: src/core/dbus-unit.c:599
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:711
+#: src/core/dbus-unit.c:708
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
@@ -950,7 +964,7 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby usunąć pliki i katalogi powiązane "
 "z jednostką „$(unit)”."
 
-#: src/core/dbus-unit.c:760
+#: src/core/dbus-unit.c:757
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
 msgstr ""
index dd268ae1b5fdb710f758daae0aeceeeb388962c1..9e430904f1124625adbd1933dee29912c9dd5399 100644 (file)
@@ -37,6 +37,7 @@ disable systemd-networkd-wait-online.service
 disable systemd-time-wait-sync.service
 disable systemd-boot-check-no-failures.service
 disable systemd-network-generator.service
+disable proc-sys-fs-binfmt_misc.mount
 
 disable syslog.socket
 
index 6e411a91f0ec9766c8351348825ca331863b3b5f..bafc3fbc846b943e77db53807553d6e8690c01fc 100644 (file)
@@ -4,7 +4,7 @@ SUBSYSTEM!="net", GOTO="net_setup_link_end"
 
 IMPORT{builtin}="path_id"
 
-ACTION!="add", GOTO="net_setup_link_end"
+ACTION=="remove", GOTO="net_setup_link_end"
 
 IMPORT{builtin}="net_setup_link"
 
index 1c60eec587040252ca41e9018372ac2e939e49b2..9e2772388dc3dc8044b1f8ed14a9d6ed2f6de1e6 100644 (file)
@@ -46,9 +46,9 @@ SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTE
 # http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n955
 
 SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name"
-SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"
+SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k", \
+  ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
 
-SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0b????:*", ENV{ID_SMARTCARD_READER}="1"
 ENV{ID_SMARTCARD_READER}=="?*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target", ENV{SYSTEMD_USER_WANTS}+="smartcard.target"
 SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target", ENV{SYSTEMD_USER_WANTS}+="sound.target"
index abffb205889656d60034354f8f406a712a7d03cc..715a5aafb1514e089672a187595c999bfb1674c8 100755 (executable)
@@ -16,11 +16,13 @@ PHASES=(${@:-SETUP RUN})
 UBUNTU_RELEASE="$(lsb_release -cs)"
 
 create_container() {
-    # create autopkgtest LXC image; this sometimes fails with "Unable to fetch
-    # GPG key from keyserver", so retry a few times
-    for retry in {1..5}; do
-        sudo lxc-create -n $CONTAINER -t download -- -d $DISTRO -r $RELEASE -a $ARCH --keyserver hkp://keyserver.ubuntu.com:80 && break
-        sleep $((retry*retry))
+    # Create autopkgtest LXC image; this sometimes fails with "Unable to fetch
+    # GPG key from keyserver", so retry a few times with different keyservers.
+    for keyserver in "" "keys.gnupg.net" "keys.openpgp.org" "keyserver.ubuntu.com"; do
+        for retry in {1..5}; do
+            sudo lxc-create -n $CONTAINER -t download -- -d $DISTRO -r $RELEASE -a $ARCH --server us.images.linuxcontainers.org ${keyserver:+--keyserver "$keyserver"} && break 2
+            sleep $((retry*retry))
+        done
     done
 
     # unconfine the container, otherwise some tests fail
index 0d3022b1e963e78f7be6ae5fb0cbbc242bef8ea5..1df70147afcb5dd24904e5db954d94ad211acc91 100644 (file)
@@ -24,6 +24,7 @@ if bashcompletiondir != 'no'
                  ['systemd-cgtop',       ''],
                  ['systemd-delta',       ''],
                  ['systemd-detect-virt', ''],
+                 ['systemd-id128',       ''],
                  ['systemd-nspawn',      ''],
                  ['systemd-path',        ''],
                  ['systemd-run',         ''],
@@ -32,6 +33,7 @@ if bashcompletiondir != 'no'
                  [bash_systemctl,        ''],
                  ['bootctl',             'ENABLE_EFI'],
                  ['coredumpctl',         'ENABLE_COREDUMP'],
+                 ['homectl',             'ENABLE_HOMED'],
                  ['hostnamectl',         'ENABLE_HOSTNAMED'],
                  ['localectl',           'ENABLE_LOCALED'],
                  ['loginctl',            'ENABLE_LOGIND'],
index b9ccbedf75b2d862c2cddf1638b05473b472cf1f..feb7016770487254727b69486b36083fe5e3c5f9 100644 (file)
@@ -35,6 +35,9 @@ for fun in session-status show-session activate lock-session unlock-session term
 _loginctl_$fun() {
     local -a _sys_all_sessions{,_descr}
 
+       _sys_all_sessions=( "self" )
+       _sys_all_sessions_descr=( "self:alias for the current session" )
+
     _loginctl_all_sessions
     for _ignore in $words[2,-1]; do
         _sys_all_sessions[(i)$_ignore]=()
@@ -81,6 +84,9 @@ done
 _loginctl_seats() {
     local -a _sys_all_seats{,_descr}
 
+       _sys_all_seats=( "self" )
+       _sys_all_seats_descr=( "self:alias for the current seat" )
+
     _loginctl_all_seats
     for _ignore in $words[2,-1]; do
         _sys_all_seats[(i)$_ignore]=()
index 16ab4f893e129bdd31b0342811a6ebd68657e167..9c1d63030d18a899c33b85a7c1b7ef8d36235c8a 100644 (file)
@@ -2185,10 +2185,10 @@ int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
                         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 (!endswith(mangled, ".service"))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Unit %s is not a service unit, refusing.",
+                                                       *i);
 
                         if (unit_name_is_valid(mangled, UNIT_NAME_TEMPLATE)) {
                                 r = unit_name_replace_instance(mangled, "test-instance", &instance);
index a9e4b37573043d1a1eddf2fc421646f19973f2fd..9a0b1a7bbfe47a7c4db6507b6a14e55a86aa39e4 100644 (file)
@@ -1248,8 +1248,7 @@ static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) {
                 }
         }
 
-        *ret = expanded_patterns;
-        expanded_patterns = NULL; /* do not free */
+        *ret = TAKE_PTR(expanded_patterns); /* do not free */
 
         return 0;
 }
@@ -1686,7 +1685,7 @@ static int load_kernel_syscalls(Set **ret) {
         return 0;
 }
 
-static void kernel_syscalls_remove(Set *s, const SyscallFilterSet *set) {
+static void syscall_set_remove(Set *s, const SyscallFilterSet *set) {
         const char *syscall;
 
         NULSTR_FOREACH(syscall, set->value) {
@@ -1717,9 +1716,14 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
         (void) pager_open(arg_pager_flags);
 
         if (strv_isempty(strv_skip(argv, 1))) {
-                _cleanup_set_free_ Set *kernel = NULL;
+                _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
+                const char *sys;
                 int i, k;
 
+                NULSTR_FOREACH(sys, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value)
+                        if (set_put_strdup(&known, sys) < 0)
+                                return log_oom();
+
                 k = load_kernel_syscalls(&kernel);
 
                 for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
@@ -1728,10 +1732,30 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
                                 puts("");
 
                         dump_syscall_filter(set);
-                        kernel_syscalls_remove(kernel, set);
+                        syscall_set_remove(kernel, set);
+                        if (i != SYSCALL_FILTER_SET_KNOWN)
+                                syscall_set_remove(known, set);
                         first = false;
                 }
 
+                if (!set_isempty(known)) {
+                        _cleanup_free_ char **l = NULL;
+                        char **syscall;
+
+                        printf("\n"
+                               "# %sUngrouped System Calls%s (known but not included in any of the groups except @known):\n",
+                               ansi_highlight(), ansi_normal());
+
+                        l = set_get_strv(known);
+                        if (!l)
+                                return log_oom();
+
+                        strv_sort(l);
+
+                        STRV_FOREACH(syscall, l)
+                                printf("#   %s\n", *syscall);
+                }
+
                 if (k < 0) {
                         fputc('\n', stdout);
                         fflush(stdout);
index 64d9e00315e5550a3a3baa8aa4632709159e5e86..34340e4a39df73d6a83e4981c40c4176e2aeb96c 100644 (file)
@@ -27,7 +27,7 @@ typedef void (*free_func_t)(void *p);
                 size_t _n_ = n;                                         \
                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca(sizeof(t)*_n_);                             \
+                (t*) alloca((sizeof(t)*_n_) ?: 1);                      \
         })
 
 #define newa0(t, n)                                                     \
@@ -35,14 +35,14 @@ typedef void (*free_func_t)(void *p);
                 size_t _n_ = n;                                         \
                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca0(sizeof(t)*_n_);                            \
+                (t*) alloca0((sizeof(t)*_n_) ?: 1);                     \
         })
 
 #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
 
 #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
 
-#define malloc0(n) (calloc(1, (n)))
+#define malloc0(n) (calloc(1, (n) ?: 1))
 
 static inline void *mfree(void *memory) {
         free(memory);
@@ -65,7 +65,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
                 void *_q_;                      \
                 size_t _l_ = l;                 \
                 assert(_l_ <= ALLOCA_MAX);      \
-                _q_ = alloca(_l_);              \
+                _q_ = alloca(_l_ ?: 1);         \
                 memcpy(_q_, p, _l_);            \
         })
 
@@ -135,7 +135,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
                 char *_new_;                            \
                 size_t _len_ = n;                       \
                 assert(_len_ <= ALLOCA_MAX);            \
-                _new_ = alloca(_len_);                  \
+                _new_ = alloca(_len_ ?: 1);             \
                 (void *) memset(_new_, 0, _len_);       \
         })
 
@@ -146,7 +146,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
                 size_t _mask_ = (align) - 1;                            \
                 size_t _size_ = size;                                   \
                 assert(_size_ <= ALLOCA_MAX);                           \
-                _ptr_ = alloca(_size_ + _mask_);                        \
+                _ptr_ = alloca((_size_ + _mask_) ?: 1);                 \
                 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
         })
 
index 43a58918e9d724f8fdab1e69fa674d27837557ec..50a35268ea1bbfd757142e51063b838cdaf2cd9b 100644 (file)
@@ -1393,13 +1393,12 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub
                 }
 
                 for (j = 0; j < n_old_parent_qgroups; j++)
-                        if (old_parent_qgroups[j] == old_qgroups[i]) {
+                        if (old_parent_qgroups[j] == old_qgroups[i])
                                 /* The old subvolume shared a common
                                  * parent qgroup with its parent
                                  * subvolume. Let's set up something
                                  * similar in the destination. */
                                 copy_from_parent = true;
-                        }
         }
 
         if (!insert_intermediary_qgroup && !copy_from_parent)
index d160af5bc7e6d7e6101c73d54853eb3c37270877..e02ad391a96abae4db1433f595b61cc1067bf299 100644 (file)
         _IDN_FEATURE_ " "                                               \
         _PCRE2_FEATURE_ " "                                             \
         _CGROUP_HIERARCHY_
+
+enum {
+        BUILD_MODE_DEVELOPER,
+        BUILD_MODE_RELEASE,
+};
index 6210347553c4088c3df20d85eb8eb00cd0b24140..d2655673fdf9351e92010a703f01a6885739d300 100644 (file)
@@ -1685,6 +1685,26 @@ int cg_get_attribute_as_uint64(const char *controller, const char *path, const c
         return 0;
 }
 
+int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret) {
+        _cleanup_free_ char *value = NULL;
+        int r;
+
+        assert(ret);
+
+        r = cg_get_attribute(controller, path, attribute, &value);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+
+        r = parse_boolean(value);
+        if (r < 0)
+                return r;
+
+        *ret = r;
+        return 0;
+}
+
 int cg_get_keyed_attribute_full(
                 const char *controller,
                 const char *path,
@@ -2161,3 +2181,10 @@ CGroupMask get_cpu_accounting_mask(void) {
 bool cpu_accounting_is_cheap(void) {
         return get_cpu_accounting_mask() == 0;
 }
+
+static const char* const managed_oom_mode_table[_MANAGED_OOM_MODE_MAX] = {
+        [MANAGED_OOM_AUTO] = "auto",
+        [MANAGED_OOM_KILL] = "kill",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(managed_oom_mode, ManagedOOMMode);
index 2b88571bc1c7767d57cc9de9d0a417fe2e0cbb82..eda2b16a1b9c8aee85fc5359976e9d61a1fad591 100644 (file)
@@ -208,6 +208,9 @@ static inline int cg_get_keyed_attribute_graceful(
 
 int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret);
 
+/* Does a parse_boolean() on the attribute contents and sets ret accordingly */
+int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret);
+
 int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
 
 int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
@@ -275,3 +278,13 @@ CGroupController cgroup_controller_from_string(const char *s) _pure_;
 
 bool is_cgroup_fs(const struct statfs *s);
 bool fd_is_cgroup_fs(int fd);
+
+typedef enum ManagedOOMMode {
+        MANAGED_OOM_AUTO,
+        MANAGED_OOM_KILL,
+        _MANAGED_OOM_MODE_MAX,
+        _MANAGED_OOM_MODE_INVALID = -1,
+} ManagedOOMMode;
+
+const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_;
+ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_;
index 843d2d7c985c081252c0278a2cfb28b50862b899..cf2efd8e7bba37073db0ec4a2613a82f0992d7c3 100644 (file)
@@ -4,6 +4,7 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
index 970654a1ade9f90658edfe16ea7a4c04fc035894..9f1f3c229c7fb90f36cf38105afa25beeacd9530 100644 (file)
@@ -63,3 +63,5 @@
                 .un.sun_family = AF_UNIX,                       \
                 .un.sun_path = "\0/org/freedesktop/plymouthd",  \
         }
+
+#define VARLINK_ADDR_PATH_MANAGED_OOM "/run/systemd/io.system.ManagedOOM"
index 179408c399402d0257767228765b46bedcc9c112..8b26b36cfe5eb0cf35ed1778d29119e4ad25741d 100644 (file)
 #include "strv.h"
 #include "utf8.h"
 
-#define VALID_CHARS_ENV_NAME                    \
+/* We follow bash for the character set. Different shells have different rules. */
+#define VALID_BASH_ENV_NAME_CHARS               \
         DIGITS LETTERS                          \
         "_"
 
-static bool env_name_is_valid_n(const char *e, size_t n) {
-        const char *p;
+static bool printable_portable_character(char c) {
+        /* POSIX.1-2008 specifies almost all ASCII characters as "portable". (Only DEL is excluded, and
+         * additionally NUL and = are not allowed in variable names). We are stricter, and additionally
+         * reject BEL, BS, HT, CR, LF, VT, FF and SPACE, i.e. all whitespace. */
+
+        return c >= '!' && c <= '~';
+}
 
+static bool env_name_is_valid_n(const char *e, size_t n) {
         if (!e)
                 return false;
 
         if (n <= 0)
                 return false;
 
-        if (e[0] >= '0' && e[0] <= '9')
-                return false;
-
         /* POSIX says the overall size of the environment block cannot
          * be > ARG_MAX, an individual assignment hence cannot be
          * either. Discounting the equal sign and trailing NUL this
@@ -40,8 +44,8 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
         if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
                 return false;
 
-        for (p = e; p < e + n; p++)
-                if (!strchr(VALID_CHARS_ENV_NAME, *p))
+        for (const char *p = e; p < e + n; p++)
+                if (!printable_portable_character(*p) || *p == '=')
                         return false;
 
         return true;
@@ -546,7 +550,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                                 word = e+1;
                                 state = WORD;
 
-                        } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
+                        } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
                                 k = strnappend(r, word, e-word-1);
                                 if (!k)
                                         return NULL;
@@ -636,7 +640,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                 case VARIABLE_RAW:
                         assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
 
-                        if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
+                        if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
                                 const char *t;
 
                                 t = strv_env_get_n(env, word+1, e-word-1, flags);
index db869cbd5499a8827e8bb72ae5d519a0a45663cb..e37b6944a8a6fe7c417e68f61ca6a9a5efddfbdc 100644 (file)
@@ -21,6 +21,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "tmpfile-util.h"
@@ -210,13 +211,102 @@ static int get_max_fd(void) {
         return (int) (m - 1);
 }
 
+static int cmp_int(const int *a, const int *b) {
+        return CMP(*a, *b);
+}
+
 int close_all_fds(const int except[], size_t n_except) {
+        static bool have_close_range = true; /* Assume we live in the future */
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
         int r = 0;
 
         assert(n_except == 0 || except);
 
+        if (have_close_range) {
+                /* In the best case we have close_range() to close all fds between a start and an end fd,
+                 * which we can use on the "inverted" exception array, i.e. all intervals between all
+                 * adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
+                 * where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep
+                 * open. Given that we assume n ≫ m that's preferable to us. */
+
+                if (n_except == 0) {
+                        /* Close everything. Yay! */
+
+                        if (close_range(3, -1, 0) >= 0)
+                                return 1;
+
+                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                return -errno;
+
+                        have_close_range = false;
+                } else {
+                        _cleanup_free_ int *sorted_malloc = NULL;
+                        size_t n_sorted;
+                        int *sorted;
+
+                        assert(n_except < SIZE_MAX);
+                        n_sorted = n_except + 1;
+
+                        if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
+                                sorted = sorted_malloc = new(int, n_sorted);
+                        else
+                                sorted = newa(int, n_sorted);
+
+                        if (sorted) {
+                                int c = 0;
+
+                                memcpy(sorted, except, n_except * sizeof(int));
+
+                                /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
+                                 * allows us to cover the head of the array the same way as the body */
+                                sorted[n_sorted-1] = 2;
+
+                                typesafe_qsort(sorted, n_sorted, cmp_int);
+
+                                for (size_t i = 0; i < n_sorted-1; i++) {
+                                        int start, end;
+
+                                        start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
+                                        end = MAX(sorted[i+1], 2);
+
+                                        assert(end >= start);
+
+                                        if (end - start <= 1)
+                                                continue;
+
+                                        /* Close everything between the start and end fds (both of which shall stay open) */
+                                        if (close_range(start + 1, end - 1, 0) < 0) {
+                                                if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                                        return -errno;
+
+                                                have_close_range = false;
+                                                break;
+                                        }
+
+                                        c += end - start - 1;
+                                }
+
+                                if (have_close_range) {
+                                        /* The loop succeeded. Let's now close everything beyond the end */
+
+                                        if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
+                                                return c;
+
+                                        if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+                                                return c + 1;
+
+                                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                                return -errno;
+
+                                        have_close_range = false;
+                                }
+                        }
+                }
+
+                /* Fallback on OOM or if close_range() is not supported */
+        }
+
         d = opendir("/proc/self/fd");
         if (!d) {
                 int fd, max_fd;
index c3d55d209ac7ede12ceaa70b943023fdb73ddaa0..050c8709f81f563870776378c751c915776110bf 100644 (file)
@@ -252,7 +252,8 @@ int write_string_file_ts(
         /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
         fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY |
                   (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
-                  (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0),
+                  (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
+                  (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0),
                   (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
         if (fd < 0) {
                 r = -errno;
@@ -940,6 +941,42 @@ 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 chase_symlinks_and_fopen_unlocked(
+                const char *path,
+                const char *root,
+                unsigned chase_flags,
+                const char *open_flags,
+                FILE **ret_file,
+                char **ret_path) {
+
+        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *final_path = NULL;
+        int mode_flags, r;
+        FILE *f;
+
+        assert(path);
+        assert(open_flags);
+        assert(ret_file);
+
+        mode_flags = mode_to_flags(open_flags);
+        if (mode_flags < 0)
+                return mode_flags;
+
+        fd = chase_symlinks_and_open(path, root, chase_flags, mode_flags, ret_path ? &final_path : NULL);
+        if (fd < 0)
+                return fd;
+
+        r = fdopen_unlocked(fd, open_flags, &f);
+        if (r < 0)
+                return r;
+        TAKE_FD(fd);
+
+        *ret_file = f;
+        if (ret_path)
+                *ret_path = TAKE_PTR(final_path);
+        return 0;
+}
+
 int fflush_and_check(FILE *f) {
         assert(f);
 
index 7d58fa7cfc24d51033edb97a3f7a4fec6d6aa5f1..963d7d08fc869913a99fb49a7c5277d7b082dafe 100644 (file)
 
 typedef enum {
         WRITE_STRING_FILE_CREATE            = 1 << 0,
-        WRITE_STRING_FILE_ATOMIC            = 1 << 1,
-        WRITE_STRING_FILE_AVOID_NEWLINE     = 1 << 2,
-        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
-        WRITE_STRING_FILE_SYNC              = 1 << 4,
-        WRITE_STRING_FILE_DISABLE_BUFFER    = 1 << 5,
-        WRITE_STRING_FILE_NOFOLLOW          = 1 << 6,
-        WRITE_STRING_FILE_MKDIR_0755        = 1 << 7,
-        WRITE_STRING_FILE_MODE_0600         = 1 << 8,
+        WRITE_STRING_FILE_TRUNCATE          = 1 << 1,
+        WRITE_STRING_FILE_ATOMIC            = 1 << 2,
+        WRITE_STRING_FILE_AVOID_NEWLINE     = 1 << 3,
+        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 4,
+        WRITE_STRING_FILE_SYNC              = 1 << 5,
+        WRITE_STRING_FILE_DISABLE_BUFFER    = 1 << 6,
+        WRITE_STRING_FILE_NOFOLLOW          = 1 << 7,
+        WRITE_STRING_FILE_MKDIR_0755        = 1 << 8,
+        WRITE_STRING_FILE_MODE_0600         = 1 << 9,
 
         /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
            more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
@@ -81,6 +82,14 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
 
+int chase_symlinks_and_fopen_unlocked(
+                const char *path,
+                const char *root,
+                unsigned chase_flags,
+                const char *open_flags,
+                FILE **ret_file,
+                char **ret_path);
+
 int fflush_and_check(FILE *f);
 int fflush_sync_and_check(FILE *f);
 
index c47fa76ea8ff2e709d1b8d92b92fe0aed0609cf8..db37c16140c82865fd1e00b622699c8675db0d67 100644 (file)
@@ -72,11 +72,14 @@ typedef enum {
         FORMAT_BYTES_TRAILING_B  = 1 << 2,
 } FormatBytesFlag;
 
-#define FORMAT_BYTES_MAX 16
+#define FORMAT_BYTES_MAX 16U
+
 char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
+
 static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
         return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
 }
+
 static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
         if (t == CGROUP_LIMIT_MAX) {
                 (void) snprintf(buf, l, "%s", "infinity");
index c20a29332a55c9b35fe8bafe41cda3916a3ce300..587b3504ee86ad7489663e881b3f8b75fca5b78a 100644 (file)
@@ -312,6 +312,25 @@ int fchmod_opath(int fd, mode_t m) {
         return 0;
 }
 
+int futimens_opath(int fd, const struct timespec ts[2]) {
+        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+
+        /* Similar to fchmod_path() but for futimens() */
+
+        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+        if (utimensat(AT_FDCWD, procfs_path, ts, 0) < 0) {
+                if (errno != ENOENT)
+                        return -errno;
+
+                if (proc_mounted() == 0)
+                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+
+                return -ENOENT;
+        }
+
+        return 0;
+}
+
 int stat_warn_permissions(const char *path, const struct stat *st) {
         assert(path);
         assert(st);
index eb6e1eee4fa018a652e8bd1b4f259a1f95d8d3b1..241cc6ef62978772cde3616c208731c0a67ca5dd 100644 (file)
@@ -38,6 +38,8 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid);
 int fchmod_umask(int fd, mode_t mode);
 int fchmod_opath(int fd, mode_t m);
 
+int futimens_opath(int fd, const struct timespec ts[2]);
+
 int fd_warn_permissions(const char *path, int fd);
 int stat_warn_permissions(const char *path, const struct stat *st);
 
@@ -79,7 +81,7 @@ enum {
         CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
         CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
         CHASE_NO_AUTOFS   = 1 << 2, /* Return -EREMOTE if autofs mount point found */
-        CHASE_SAFE        = 1 << 3, /* Return EPERM if we ever traverse from unprivileged to privileged files or directories */
+        CHASE_SAFE        = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
         CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
         CHASE_STEP        = 1 << 5, /* Just execute a single step of the normalization */
         CHASE_NOFOLLOW    = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
index cf279e5cbefc5673d66ca7369084d4682a12ff64..83016c0fd616ad74047a24b41abe2c08ffcb0bf8 100644 (file)
@@ -71,6 +71,19 @@ const struct hash_ops trivial_hash_ops = {
         .compare = trivial_compare_func,
 };
 
+const struct hash_ops trivial_hash_ops_free = {
+        .hash = trivial_hash_func,
+        .compare = trivial_compare_func,
+        .free_key = free,
+};
+
+const struct hash_ops trivial_hash_ops_free_free = {
+        .hash = trivial_hash_func,
+        .compare = trivial_compare_func,
+        .free_key = free,
+        .free_value = free,
+};
+
 void uint64_hash_func(const uint64_t *p, struct siphash *state) {
         siphash24_compress(p, sizeof(uint64_t), state);
 }
index 005d1b21d21ea0806ccda6f66ccaf104edc2369d..fb602009416ea10f3e24a5fa08b2a67b49c3d489 100644 (file)
@@ -88,6 +88,8 @@ extern const struct hash_ops path_hash_ops_free;
 void trivial_hash_func(const void *p, struct siphash *state);
 int trivial_compare_func(const void *a, const void *b) _const_;
 extern const struct hash_ops trivial_hash_ops;
+extern const struct hash_ops trivial_hash_ops_free;
+extern const struct hash_ops trivial_hash_ops_free_free;
 
 /* 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. */
index 77cebd9f158c2799bb9c3da808eeb7dab944f121..61946cea326fc7fe1d4e951b944e82a34cd79b41 100644 (file)
@@ -1794,10 +1794,10 @@ int set_consume(Set *s, void *value) {
         return r;
 }
 
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG_PARAMS) {
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v  HASHMAP_DEBUG_PARAMS) {
         int r;
 
-        r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free  HASHMAP_DEBUG_PASS_ARGS);
+        r = _hashmap_ensure_allocated(h, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
@@ -1828,14 +1828,14 @@ int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG
         return r;
 }
 
-int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p  HASHMAP_DEBUG_PARAMS) {
         char *c;
         int r;
 
         assert(s);
         assert(p);
 
-        r = _set_ensure_allocated(s, &string_hash_ops_free  HASHMAP_DEBUG_PASS_ARGS);
+        r = _set_ensure_allocated(s, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
@@ -1849,14 +1849,14 @@ int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS) {
         return set_consume(*s, c);
 }
 
-int _set_put_strdupv(Set **s, char **l  HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HASHMAP_DEBUG_PARAMS) {
         int n = 0, r;
         char **i;
 
         assert(s);
 
         STRV_FOREACH(i, l) {
-                r = _set_put_strdup(s, *i  HASHMAP_DEBUG_PASS_ARGS);
+                r = _set_put_strdup_full(s, hash_ops, *i  HASHMAP_DEBUG_PASS_ARGS);
                 if (r < 0)
                         return r;
 
index 890f90a9d11a5c4aa6253445b2f50ff8f3ec657d..6933c0b1e62b41e8cfe910b1be55426ee3fb5e66 100644 (file)
@@ -153,8 +153,9 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
         return hashmap_put(PLAIN_HASHMAP(h), key, value);
 }
 
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG_PARAMS);
-#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v  HASHMAP_DEBUG_PARAMS);
+#define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v  HASHMAP_DEBUG_SRC_ARGS)
+#define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v)
 
 int hashmap_update(Hashmap *h, const void *key, void *value);
 static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
index e893298d6868a676f3d3e3b23f0cba0a7a8f9a1c..dbae418282b7c8ccd5f066d6bcd5d8a8a97c932e 100644 (file)
@@ -160,8 +160,7 @@ int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size
         /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
         (void) send(h->fd, NULL, 0, 0);
 
-        *ret = h;
-        h = NULL;
+        *ret = TAKE_PTR(h);
 
         return 0;
 }
diff --git a/src/basic/linux/ipv6_route.h b/src/basic/linux/ipv6_route.h
new file mode 100644 (file)
index 0000000..593800a
--- /dev/null
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *     Linux INET6 implementation 
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_IPV6_ROUTE_H
+#define _UAPI_LINUX_IPV6_ROUTE_H
+
+#include <linux/types.h>
+#include <linux/in6.h>                 /* For struct in6_addr. */
+
+#define RTF_DEFAULT    0x00010000      /* default - learned via ND     */
+#define RTF_ALLONLINK  0x00020000      /* (deprecated and will be removed)
+                                          fallback, no routers on link */
+#define RTF_ADDRCONF   0x00040000      /* addrconf route - RA          */
+#define RTF_PREFIX_RT  0x00080000      /* A prefix only route - RA     */
+#define RTF_ANYCAST    0x00100000      /* Anycast                      */
+
+#define RTF_NONEXTHOP  0x00200000      /* route with no nexthop        */
+#define RTF_EXPIRES    0x00400000
+
+#define RTF_ROUTEINFO  0x00800000      /* route information - RA       */
+
+#define RTF_CACHE      0x01000000      /* read-only: can not be set by user */
+#define RTF_FLOW       0x02000000      /* flow significant route       */
+#define RTF_POLICY     0x04000000      /* policy route                 */
+
+#define RTF_PREF(pref) ((pref) << 27)
+#define RTF_PREF_MASK  0x18000000
+
+#define RTF_PCPU       0x40000000      /* read-only: can not be set by user */
+#define RTF_LOCAL      0x80000000
+
+
+struct in6_rtmsg {
+       struct in6_addr         rtmsg_dst;
+       struct in6_addr         rtmsg_src;
+       struct in6_addr         rtmsg_gateway;
+       __u32                   rtmsg_type;
+       __u16                   rtmsg_dst_len;
+       __u16                   rtmsg_src_len;
+       __u32                   rtmsg_metric;
+       unsigned long           rtmsg_info;
+        __u32                  rtmsg_flags;
+       int                     rtmsg_ifindex;
+};
+
+#define RTMSG_NEWDEVICE                0x11
+#define RTMSG_DELDEVICE                0x12
+#define RTMSG_NEWROUTE         0x21
+#define RTMSG_DELROUTE         0x22
+
+#define IP6_RT_PRIO_USER       1024
+#define IP6_RT_PRIO_ADDRCONF   256
+
+#endif /* _UAPI_LINUX_IPV6_ROUTE_H */
diff --git a/src/basic/linux/loadavg.h b/src/basic/linux/loadavg.h
new file mode 100644 (file)
index 0000000..521a787
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SCHED_LOADAVG_H
+#define _LINUX_SCHED_LOADAVG_H
+
+/*
+ * These are the constant used to fake the fixed-point load-average
+ * counting. Some notes:
+ *  - 11 bit fractions expand to 22 bits by the multiplies: this gives
+ *    a load-average precision of 10 bits integer + 11 bits fractional
+ *  - if you want to count load-averages more often, you need more
+ *    precision, or rounding will get you. With 2-second counting freq,
+ *    the EXP_n values would be 1981, 2034 and 2043 if still using only
+ *    11 bit fractions.
+ */
+extern unsigned long avenrun[];                 /* Load averages */
+extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift);
+
+#define FSHIFT          11                      /* nr of bits of precision */
+#define FIXED_1         (1<<FSHIFT)             /* 1.0 as fixed-point */
+#define LOAD_FREQ       (5*HZ+1)                /* 5 sec intervals */
+#define EXP_1           1884                    /* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5           2014                    /* 1/exp(5sec/5min) */
+#define EXP_15          2037                    /* 1/exp(5sec/15min) */
+
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
+static inline unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
+{
+        unsigned long newload;
+
+        newload = load * exp + active * (FIXED_1 - exp);
+        if (active >= load)
+                newload += FIXED_1-1;
+
+        return newload / FIXED_1;
+}
+
+extern unsigned long calc_load_n(unsigned long load, unsigned long exp,
+                                 unsigned long active, unsigned int n);
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+extern void calc_global_load(unsigned long ticks);
+
+#endif /* _LINUX_SCHED_LOADAVG_H */
index 899a8423f22d6eea59d84e2ca04a34a857b3ff6a..1d796c518079446309915c520f78828083b1a265 100644 (file)
@@ -22,6 +22,7 @@
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing_syscall.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
 #include "process-util.h"
@@ -53,6 +54,7 @@ static bool syslog_is_stream = false;
 static bool show_color = false;
 static bool show_location = false;
 static bool show_time = false;
+static bool show_tid = false;
 
 static bool upgrade_syslog_to_journal = false;
 static bool always_reopen_console = false;
@@ -265,28 +267,39 @@ int log_open(void) {
                 return 0;
         }
 
-        if (log_target != LOG_TARGET_AUTO || getpid_cached() == 1 || stderr_is_journal()) {
-
-                if (!prohibit_ipc &&
-                    IN_SET(log_target, LOG_TARGET_AUTO,
-                                       LOG_TARGET_JOURNAL_OR_KMSG,
-                                       LOG_TARGET_JOURNAL)) {
-                        r = log_open_journal();
-                        if (r >= 0) {
-                                log_close_syslog();
-                                log_close_console();
-                                return r;
+        if (getpid_cached() == 1 ||
+            stderr_is_journal() ||
+            IN_SET(log_target,
+                   LOG_TARGET_KMSG,
+                   LOG_TARGET_JOURNAL,
+                   LOG_TARGET_JOURNAL_OR_KMSG,
+                   LOG_TARGET_SYSLOG,
+                   LOG_TARGET_SYSLOG_OR_KMSG)) {
+
+                if (!prohibit_ipc) {
+                        if (IN_SET(log_target,
+                                   LOG_TARGET_AUTO,
+                                   LOG_TARGET_JOURNAL_OR_KMSG,
+                                   LOG_TARGET_JOURNAL)) {
+
+                                r = log_open_journal();
+                                if (r >= 0) {
+                                        log_close_syslog();
+                                        log_close_console();
+                                        return r;
+                                }
                         }
-                }
 
-                if (!prohibit_ipc &&
-                    IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
-                                       LOG_TARGET_SYSLOG)) {
-                        r = log_open_syslog();
-                        if (r >= 0) {
-                                log_close_journal();
-                                log_close_console();
-                                return r;
+                        if (IN_SET(log_target,
+                                   LOG_TARGET_SYSLOG_OR_KMSG,
+                                   LOG_TARGET_SYSLOG)) {
+
+                                r = log_open_syslog();
+                                if (r >= 0) {
+                                        log_close_journal();
+                                        log_close_console();
+                                        return r;
+                                }
                         }
                 }
 
@@ -360,8 +373,9 @@ static int write_to_console(
 
         char location[256],
              header_time[FORMAT_TIMESTAMP_MAX],
-             prefix[1 + DECIMAL_STR_MAX(int) + 2];
-        struct iovec iovec[8] = {};
+             prefix[1 + DECIMAL_STR_MAX(int) + 2],
+             tid_string[3 + DECIMAL_STR_MAX(pid_t) + 1];
+        struct iovec iovec[9];
         const char *on = NULL, *off = NULL;
         size_t n = 0;
 
@@ -380,6 +394,11 @@ static int write_to_console(
                 }
         }
 
+        if (show_tid) {
+                xsprintf(tid_string, "(" PID_FMT ") ", gettid());
+                iovec[n++] = IOVEC_MAKE_STRING(tid_string);
+        }
+
         if (show_color)
                 get_log_colors(LOG_PRI(level), &on, &off, NULL);
 
@@ -539,6 +558,7 @@ static int log_do_header(
         r = snprintf(header, size,
                      "PRIORITY=%i\n"
                      "SYSLOG_FACILITY=%i\n"
+                     "TID=" PID_FMT "\n"
                      "%s%.256s%s"        /* CODE_FILE */
                      "%s%.*i%s"          /* CODE_LINE */
                      "%s%.256s%s"        /* CODE_FUNC */
@@ -548,6 +568,7 @@ static int log_do_header(
                      "SYSLOG_IDENTIFIER=%.256s\n",
                      LOG_PRI(level),
                      LOG_FAC(level),
+                     gettid(),
                      isempty(file) ? "" : "CODE_FILE=",
                      isempty(file) ? "" : file,
                      isempty(file) ? "" : "\n",
@@ -1133,6 +1154,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (log_show_location_from_string(value ?: "1") < 0)
                         log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
 
+        } else if (proc_cmdline_key_streq(key, "systemd.log_tid")) {
+
+                if (log_show_tid_from_string(value ?: "1") < 0)
+                        log_warning("Failed to parse log tid setting '%s'. Ignoring.", value);
+
         } else if (proc_cmdline_key_streq(key, "systemd.log_time")) {
 
                 if (log_show_time_from_string(value ?: "1") < 0)
@@ -1177,6 +1203,10 @@ void log_parse_environment_cli_realm(LogRealm realm) {
         e = getenv("SYSTEMD_LOG_TIME");
         if (e && log_show_time_from_string(e) < 0)
                 log_warning("Failed to parse log time '%s'. Ignoring.", e);
+
+        e = getenv("SYSTEMD_LOG_TID");
+        if (e && log_show_tid_from_string(e) < 0)
+                log_warning("Failed to parse log tid '%s'. Ignoring.", e);
 }
 
 LogTarget log_get_target(void) {
@@ -1211,6 +1241,14 @@ bool log_get_show_time(void) {
         return show_time;
 }
 
+void log_show_tid(bool b) {
+        show_tid = b;
+}
+
+bool log_get_show_tid(void) {
+        return show_tid;
+}
+
 int log_show_color_from_string(const char *e) {
         int t;
 
@@ -1244,6 +1282,17 @@ int log_show_time_from_string(const char *e) {
         return 0;
 }
 
+int log_show_tid_from_string(const char *e) {
+        int t;
+
+        t = parse_boolean(e);
+        if (t < 0)
+                return t;
+
+        log_show_tid(t);
+        return 0;
+}
+
 bool log_on_console(void) {
         if (IN_SET(log_target, LOG_TARGET_CONSOLE,
                                LOG_TARGET_CONSOLE_PREFIXED))
index 137d21005d415f32a3d33f146d7ad9addac7102f..ce8bb42ea175c5d345d75f8051c92e273f1a32f2 100644 (file)
@@ -30,7 +30,7 @@ typedef enum LogTarget{
         LOG_TARGET_JOURNAL_OR_KMSG,
         LOG_TARGET_SYSLOG,
         LOG_TARGET_SYSLOG_OR_KMSG,
-        LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */
+        LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
         LOG_TARGET_NULL,
         _LOG_TARGET_MAX,
         _LOG_TARGET_INVALID = -1
@@ -61,10 +61,13 @@ void log_show_location(bool b);
 bool log_get_show_location(void) _pure_;
 void log_show_time(bool b);
 bool log_get_show_time(void) _pure_;
+void log_show_tid(bool b);
+bool log_get_show_tid(void) _pure_;
 
 int log_show_color_from_string(const char *e);
 int log_show_location_from_string(const char *e);
 int log_show_time_from_string(const char *e);
+int log_show_tid_from_string(const char *e);
 
 LogTarget log_get_target(void) _pure_;
 int log_get_max_level_realm(LogRealm realm) _pure_;
index 41c2c3289e8f2094f8648dd4767fb19c8d16b701..cffc5ec59c5ea39e68de84eed258f5c1438110fa 100644 (file)
 #endif
 
 /* Temporarily disable some warnings */
+#define DISABLE_WARNING_DEPRECATED_DECLARATIONS                         \
+        _Pragma("GCC diagnostic push");                                 \
+        _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+
 #define DISABLE_WARNING_FORMAT_NONLITERAL                               \
         _Pragma("GCC diagnostic push");                                 \
         _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
@@ -277,6 +281,12 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
                 MAX(_c, z);                             \
         })
 
+#define MAX4(x, y, z, a)                                \
+        ({                                              \
+                const typeof(x) _d = MAX3(x, y, z);     \
+                MAX(_d, a);                             \
+        })
+
 #undef MIN
 #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
 #define __MIN(aq, a, bq, b)                             \
@@ -440,6 +450,9 @@ static inline int __coverity_check_and_return__(int condition) {
 #define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p)))
 #define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u)))
 
+#define PTR_TO_UINT8(p) ((uint8_t) ((uintptr_t) (p)))
+#define UINT8_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+
 #define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p)))
 #define INT32_TO_PTR(u) ((void *) ((intptr_t) (u)))
 #define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
@@ -541,10 +554,13 @@ static inline int __coverity_check_and_return__(int condition) {
 #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
 #define STRV_MAKE_EMPTY ((char*[1]) { NULL })
 
-/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */
-#define FOREACH_POINTER(p, x, ...)                                                      \
-        for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \
-             p != (typeof(p)) (void*) -1;                                               \
+/* Pointers range from NULL to POINTER_MAX */
+#define POINTER_MAX ((void*) UINTPTR_MAX)
+
+/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses POINTER_MAX as internal marker for EOL. */
+#define FOREACH_POINTER(p, x, ...)                                                       \
+        for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, POINTER_MAX }; \
+             p != (typeof(p)) POINTER_MAX;                                               \
              p = *(++_l))
 
 /* Define C11 thread_local attribute even on older gcc compiler
@@ -634,4 +650,8 @@ static inline int __coverity_check_and_return__(int condition) {
                 _copy;                                                  \
         })
 
+static inline size_t size_add(size_t x, size_t y) {
+        return y >= SIZE_MAX - x ? SIZE_MAX : x + y;
+}
+
 #include "log.h"
index 42d0754d6d1891e29a88f3e943f34e43605586ad..d83c1ae496b7a0049a42abe97f6b0249358540c9 100644 (file)
@@ -91,9 +91,11 @@ basic_sources = files('''
         limits-util.h
         linux/btrfs.h
         linux/btrfs_tree.h
+        linux/can/netlink.h
         linux/can/vxcan.h
         linux/fib_rules.h
         linux/fou.h
+        linux/hdlc/ioctl.h
         linux/if.h
         linux/if_addr.h
         linux/if_arp.h
@@ -106,8 +108,10 @@ basic_sources = files('''
         linux/if_tunnel.h
         linux/in.h
         linux/in6.h
+        linux/ipv6_route.h
         linux/l2tp.h
         linux/libc-compat.h
+        linux/loadavg.h
         linux/netdevice.h
         linux/netlink.h
         linux/rtnetlink.h
@@ -329,6 +333,7 @@ libbasic = static_library(
         dependencies : [versiondep,
                         threads,
                         libcap,
+                        libseccomp,
                         libselinux,
                         libm,
                         libdl],
index c52cd449339cad29df48a629ccc5eb824cc614ad..4d37618741f741052f66ba29b5bff6260ed96f3e 100644 (file)
@@ -27,7 +27,7 @@
 
 #ifdef CAP_LAST_CAP
 #  if CAP_LAST_CAP > SYSTEMD_CAP_LAST_CAP
-#    if DEVELOPER_MODE && defined(TEST_CAPABILITY_C)
+#    if BUILD_MODE == BUILD_MODE_DEVELOPER && defined(TEST_CAPABILITY_C)
 #      warning "The capability list here is outdated"
 #    endif
 #  else
index a2acdc6c95fa31c3c6d1c8d9524c030855548353..01fec6f2f5d1f7190c1512c3d0da87835efea0d5 100644 (file)
 #include <asm/sgidefs.h>
 #endif
 
+#if defined(__x86_64__) && defined(__ILP32__)
+#define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000)
+#else
+#define systemd_SC_arch_bias(x) (x)
+#endif
+
 #include "missing_keyctl.h"
 #include "missing_stat.h"
 
@@ -34,7 +40,7 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old)
 /* ======================================================================= */
 
 #if defined __x86_64__
-#  define systemd_NR_memfd_create 319
+#  define systemd_NR_memfd_create systemd_SC_arch_bias(319)
 #elif defined __arm__
 #  define systemd_NR_memfd_create 385
 #elif defined __aarch64__
@@ -91,7 +97,7 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
 /* ======================================================================= */
 
 #if defined __x86_64__
-#  define systemd_NR_getrandom 318
+#  define systemd_NR_getrandom systemd_SC_arch_bias(318)
 #elif defined(__i386__)
 #  define systemd_NR_getrandom 355
 #elif defined(__arm__)
@@ -167,7 +173,7 @@ static inline pid_t missing_gettid(void) {
 /* ======================================================================= */
 
 #if defined(__x86_64__)
-#  define systemd_NR_name_to_handle_at 303
+#  define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
 #elif defined(__i386__)
 #  define systemd_NR_name_to_handle_at 341
 #elif defined(__arm__)
@@ -224,7 +230,7 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
 #elif defined __arm__
 #  define systemd_NR_setns 375
 #elif defined(__x86_64__)
-#  define systemd_NR_setns 308
+#  define systemd_NR_setns systemd_SC_arch_bias(308)
 #elif defined(__i386__)
 #  define systemd_NR_setns 346
 #elif defined(__powerpc__)
@@ -277,7 +283,7 @@ static inline pid_t raw_getpid(void) {
 /* ======================================================================= */
 
 #if defined __x86_64__
-#  define systemd_NR_renameat2 316
+#  define systemd_NR_renameat2 systemd_SC_arch_bias(316)
 #elif defined __arm__
 #  define systemd_NR_renameat2 382
 #elif defined __aarch64__
@@ -386,7 +392,7 @@ static inline key_serial_t missing_request_key(const char *type, const char *des
 /* ======================================================================= */
 
 #if defined(__x86_64__)
-#  define systemd_NR_copy_file_range 326
+#  define systemd_NR_copy_file_range systemd_SC_arch_bias(326)
 #elif defined(__i386__)
 #  define systemd_NR_copy_file_range 377
 #elif defined __s390__
@@ -438,7 +444,7 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
 #if defined __i386__
 #  define systemd_NR_bpf 357
 #elif defined __x86_64__
-#  define systemd_NR_bpf 321
+#  define systemd_NR_bpf systemd_SC_arch_bias(321)
 #elif defined __aarch64__
 #  define systemd_NR_bpf 280
 #elif defined __arm__
@@ -490,7 +496,7 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
 #  if defined __i386__
 #    define systemd_NR_pkey_mprotect 380
 #  elif defined __x86_64__
-#    define systemd_NR_pkey_mprotect 329
+#    define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329)
 #  elif defined __aarch64__
 #    define systemd_NR_pkey_mprotect 288
 #  elif defined __arm__
@@ -543,7 +549,7 @@ assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
 #elif defined __sparc__
 #  define systemd_NR_statx 360
 #elif defined __x86_64__
-#  define systemd_NR_statx 332
+#  define systemd_NR_statx systemd_SC_arch_bias(332)
 #else
 #  warning "statx() syscall number unknown for your architecture"
 #endif
@@ -628,10 +634,22 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
 /* ======================================================================= */
 
 /* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */
-#if defined(__alpha__)
+#if defined __alpha__
 #  define systemd_NR_pidfd_send_signal 534
+#elif defined _MIPS_SIM
+#  if _MIPS_SIM == _MIPS_SIM_ABI32     /* o32 */
+#    define systemd_NR_pidfd_send_signal (424 + 4000)
+#  endif
+#  if _MIPS_SIM == _MIPS_SIM_NABI32    /* n32 */
+#    define systemd_NR_pidfd_send_signal (424 + 6000)
+#  endif
+#  if _MIPS_SIM == _MIPS_SIM_ABI64     /* n64 */
+#    define systemd_NR_pidfd_send_signal (424 + 5000)
+#  endif
+#elif defined __ia64__
+#  define systemd_NR_pidfd_send_signal (424 + 1024)
 #else
-#  define systemd_NR_pidfd_send_signal 424
+#  define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424)
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -648,7 +666,7 @@ assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
 
 #if !HAVE_PIDFD_SEND_SIGNAL
 static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-#  ifdef __NR_pidfd_open
+#  ifdef __NR_pidfd_send_signal
         return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
 #  else
         errno = ENOSYS;
@@ -660,10 +678,22 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un
 #endif
 
 /* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */
-#if defined(__alpha__)
+#if defined __alpha__
 #  define systemd_NR_pidfd_open 544
+#elif defined _MIPS_SIM
+#  if _MIPS_SIM == _MIPS_SIM_ABI32     /* o32 */
+#    define systemd_NR_pidfd_open (434 + 4000)
+#  endif
+#  if _MIPS_SIM == _MIPS_SIM_NABI32    /* n32 */
+#    define systemd_NR_pidfd_open (434 + 6000)
+#  endif
+#  if _MIPS_SIM == _MIPS_SIM_ABI64     /* n64 */
+#    define systemd_NR_pidfd_open (434 + 5000)
+#  endif
+#elif defined __ia64__
+#  define systemd_NR_pidfd_open (434 + 1024)
 #else
-#  define systemd_NR_pidfd_open 434
+#  define systemd_NR_pidfd_open systemd_SC_arch_bias(434)
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -704,3 +734,49 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
 
 #  define rt_sigqueueinfo missing_rt_sigqueueinfo
 #endif
+
+/* ======================================================================= */
+
+#define systemd_NR_close_range systemd_SC_arch_bias(436)
+
+/* may be (invalid) negative number due to libseccomp, see PR 13319 */
+#if defined __NR_close_range && __NR_close_range >= 0
+#  if defined systemd_NR_close_range
+assert_cc(__NR_close_range == systemd_NR_close_range);
+#  endif
+#else
+#  if defined __NR_close_range
+#    undef __NR_close_range
+#  endif
+#  if defined systemd_NR_close_range
+#    define __NR_close_range systemd_NR_close_range
+#  endif
+#endif
+
+#if !HAVE_CLOSE_RANGE
+static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
+#  ifdef __NR_close_range
+        /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
+         * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
+         * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
+         * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
+         * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
+         * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
+         * any other negative values. */
+        if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
+                errno = -EBADF;
+                return -1;
+        }
+
+        return syscall(__NR_close_range,
+                       (unsigned) first_fd,
+                       end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
+                       flags);
+#  else
+        errno = ENOSYS;
+        return -1;
+#  endif
+}
+
+#  define close_range missing_close_range
+#endif
index 818c9054d6e4d6d21b44137b98d3fbc1fd2f7d2e..dca2ef9f92adb49a7dcf1393e6b42003d90069a3 100644 (file)
@@ -862,3 +862,45 @@ int parse_oom_score_adjust(const char *s, int *ret) {
         *ret = v;
         return 0;
 }
+
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
+        assert(ret);
+
+        if (i >= (~0UL << FSHIFT))
+                return -ERANGE;
+
+        i = i << FSHIFT;
+        f = DIV_ROUND_UP((f << FSHIFT), 100);
+
+        if (f >= FIXED_1)
+                return -ERANGE;
+
+        *ret = i | f;
+        return 0;
+}
+
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
+        const char *d, *f_str, *i_str;
+        unsigned long i, f;
+        int r;
+
+        assert(s);
+        assert(ret);
+
+        d = strchr(s, '.');
+        if (!d)
+                return -EINVAL;
+
+        i_str = strndupa(s, d - s);
+        f_str = d + 1;
+
+        r = safe_atolu_full(i_str, 10, &i);
+        if (r < 0)
+                return r;
+
+        r = safe_atolu_full(f_str, 10, &f);
+        if (r < 0)
+                return r;
+
+        return store_loadavg_fixed_point(i, f, ret);
+}
index 2cee65c49ae36b6dafc091b4a57c4253d281c1dd..f22a19c5c6eb1d74124c6bd348212d3434f396d3 100644 (file)
@@ -3,12 +3,15 @@
 
 #include <inttypes.h>
 #include <limits.h>
+#include <linux/loadavg.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <sys/types.h>
 
 #include "macro.h"
 
+typedef unsigned long loadavg_t;
+
 int parse_boolean(const char *v) _pure_;
 int parse_dev(const char *s, dev_t *ret);
 int parse_pid(const char *s, pid_t* ret_pid);
@@ -88,18 +91,18 @@ static inline int safe_atoux64(const char *s, uint64_t *ret) {
 }
 
 #if LONG_MAX == INT_MAX
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, long unsigned *ret_u) {
         assert_cc(sizeof(unsigned long) == sizeof(unsigned));
-        return safe_atou(s, (unsigned*) ret_u);
+        return safe_atou_full(s, base, (unsigned*) ret_u);
 }
 static inline int safe_atoli(const char *s, long int *ret_u) {
         assert_cc(sizeof(long int) == sizeof(int));
         return safe_atoi(s, (int*) ret_u);
 }
 #else
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *ret_u) {
         assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
-        return safe_atollu(s, (unsigned long long*) ret_u);
+        return safe_atollu_full(s, base, (unsigned long long*) ret_u);
 }
 static inline int safe_atoli(const char *s, long int *ret_u) {
         assert_cc(sizeof(long int) == sizeof(long long int));
@@ -107,6 +110,10 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
 }
 #endif
 
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+        return safe_atolu_full(s, 0, ret_u);
+}
+
 #if SIZE_MAX == UINT_MAX
 static inline int safe_atozu(const char *s, size_t *ret_u) {
         assert_cc(sizeof(size_t) == sizeof(unsigned));
@@ -137,3 +144,8 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
 int parse_ip_prefix_length(const char *s, int *ret);
 
 int parse_oom_score_adjust(const char *s, int *ret);
+
+/* Given a Linux load average (e.g. decimal number 34.89 where 34 is passed as i and 89 is passed as f), convert it
+ * to a loadavg_t. */
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret);
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret);
index 3ea851c338547febf4d929fb4adb74e4b0048e75..e763fd7993f210a1a6d51cb4aba3de6e207c6a60 100644 (file)
@@ -181,10 +181,10 @@ static char** user_dirs(
         if (strv_extend(&res, generator_early) < 0)
                 return NULL;
 
-        if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
+        if (strv_extend(&res, persistent_config) < 0)
                 return NULL;
 
-        if (strv_extend(&res, persistent_config) < 0)
+        if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
                 return NULL;
 
         /* global config has lower priority than the user config of the same type */
index a36cf8332c2df79fa1557bbe0d32138a886fed19..95c9d5863c949016d2e7afa581b2094967cfdd2c 100644 (file)
@@ -550,7 +550,7 @@ char* path_join_internal(const char *first, ...) {
 
         sz = strlen_ptr(first);
         va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != (const char*) -1)
+        while ((p = va_arg(ap, char*)) != POINTER_MAX)
                 if (!isempty(p))
                         sz += 1 + strlen(p);
         va_end(ap);
@@ -570,7 +570,7 @@ char* path_join_internal(const char *first, ...) {
         }
 
         va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != (const char*) -1) {
+        while ((p = va_arg(ap, char*)) != POINTER_MAX) {
                 if (isempty(p))
                         continue;
 
index bd8c14903e54094761f71121a71e5eb6e28f33a5..ced0d2af40b2c9565392083cf4173386d358a105 100644 (file)
@@ -62,7 +62,7 @@ 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_internal(const char *first, ...);
-#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
+#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX)
 
 char* path_simplify(char *path, bool kill_dots);
 
index 4e04e04426256a869102bb60da0490f1ec19bdc7..2e94eed843c60d6d747413482d90c5ab399fbb9d 100644 (file)
@@ -13,7 +13,7 @@ bool ratelimit_below(RateLimit *r) {
 
         assert(r);
 
-        if (r->interval <= 0 || r->burst <= 0)
+        if (!ratelimit_configured(r))
                 return true;
 
         ts = now(CLOCK_MONOTONIC);
index 79e33b6a62ea87bf3db26e7d51120542f10c9397..9d409b04b3bb33fd81f5f28b516b05d5ebd84be2 100644 (file)
@@ -17,4 +17,8 @@ static inline void ratelimit_reset(RateLimit *rl) {
         rl->num = rl->begin = 0;
 }
 
+static inline bool ratelimit_configured(RateLimit *rl) {
+        return rl->interval > 0 && rl->burst > 0;
+}
+
 bool ratelimit_below(RateLimit *r);
index 01ff6bb331fd277d6c7de18eb35f5ea88257c52b..ab331cd677ac2207580198a42978f23838a59149 100644 (file)
@@ -45,7 +45,7 @@ static int unlinkat_harder(
                 return -errno;
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
-        if ((st.st_mode & 0700) == 0700) /* Already set? */
+        if (FLAGS_SET(st.st_mode, 0700)) /* Already set? */
                 return -EACCES; /* original error */
         if (st.st_uid != geteuid())  /* this only works if the UID matches ours */
                 return -EACCES;
index 9b3b15d387d452e6387ae619bf1840f659465f54..1791aeecde79a5b69c3d0dfb6d38639481a1719f 100644 (file)
@@ -84,14 +84,25 @@ void mac_selinux_retest(void) {
 }
 
 #if HAVE_SELINUX
+#  if HAVE_MALLINFO
+static struct mallinfo mallinfo_nowarn(void) {
+        /* glibc has deprecated mallinfo(), but the replacement malloc_info() returns an XML blob ;=[ */
+DISABLE_WARNING_DEPRECATED_DECLARATIONS
+        return mallinfo();
+REENABLE_WARNING
+}
+#  else
+#    warning "mallinfo() is missing, add mallinfo2() supported instead."
+#  endif
+
 static int open_label_db(void) {
         struct selabel_handle *hnd;
         usec_t before_timestamp, after_timestamp;
-        struct mallinfo before_mallinfo, after_mallinfo;
         char timespan[FORMAT_TIMESPAN_MAX];
-        int l;
 
-        before_mallinfo = mallinfo();
+#  if HAVE_MALLINFO
+        struct mallinfo before_mallinfo = mallinfo_nowarn();
+#  endif
         before_timestamp = now(CLOCK_MONOTONIC);
 
         hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
@@ -99,13 +110,16 @@ static int open_label_db(void) {
                 return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
 
         after_timestamp = now(CLOCK_MONOTONIC);
-        after_mallinfo = mallinfo();
-
-        l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
-
+#  if HAVE_MALLINFO
+        struct mallinfo after_mallinfo = mallinfo_nowarn();
+        int l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
         log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
                   format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
-                  (l+1023)/1024);
+                  DIV_ROUND_UP(l, 1024));
+#  else
+        log_debug("Successfully loaded SELinux database in %s.",
+                  format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0));
+#  endif
 
         /* release memory after measurement */
         if (label_hnd)
@@ -205,14 +219,11 @@ static int mac_selinux_reload(int seqno) {
 
 int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
 
+        assert(path);
+        assert(inside_path);
+
 #if HAVE_SELINUX
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-        _cleanup_freecon_ char* fcon = NULL;
         _cleanup_close_ int fd = -1;
-        struct stat st;
-        int r;
-
-        assert(path);
 
         /* if mac_selinux_init() wasn't called before we are a NOOP */
         if (!label_hnd)
@@ -227,6 +238,27 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
                 return -errno;
         }
 
+        return mac_selinux_fix_container_fd(fd, path, inside_path, flags);
+#endif
+
+        return 0;
+}
+
+int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags) {
+
+        assert(fd >= 0);
+        assert(inside_path);
+
+#if HAVE_SELINUX
+        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+        _cleanup_freecon_ char* fcon = NULL;
+        struct stat st;
+        int r;
+
+        /* if mac_selinux_init() wasn't called before we are a NOOP */
+        if (!label_hnd)
+                return 0;
+
         if (fstat(fd, &st) < 0)
                 return -errno;
 
@@ -234,12 +266,11 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
         mac_selinux_maybe_reload();
 
         if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
-                r = -errno;
-
                 /* If there's no label to set, then exit without warning */
-                if (r == -ENOENT)
+                if (errno == ENOENT)
                         return 0;
 
+                r = -errno;
                 goto fail;
         }
 
@@ -247,16 +278,16 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
         if (setfilecon_raw(procfs_path, fcon) < 0) {
                 _cleanup_freecon_ char *oldcon = NULL;
 
-                r = -errno;
-
                 /* If the FS doesn't support labels, then exit without warning */
-                if (r == -EOPNOTSUPP)
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
                         return 0;
 
                 /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
-                if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
+                if (errno == EROFS && (flags & LABEL_IGNORE_EROFS))
                         return 0;
 
+                r = -errno;
+
                 /* If the old label is identical to the new one, suppress any kind of error */
                 if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon))
                         return 0;
@@ -267,7 +298,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
         return 0;
 
 fail:
-        return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
+        return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", strna(path), strna(inside_path));
 #endif
 
         return 0;
@@ -275,11 +306,12 @@ fail:
 
 int mac_selinux_apply(const char *path, const char *label) {
 
+        assert(path);
+
 #if HAVE_SELINUX
         if (!mac_selinux_use())
                 return 0;
 
-        assert(path);
         assert(label);
 
         if (setfilecon(path, label) < 0)
@@ -288,6 +320,22 @@ int mac_selinux_apply(const char *path, const char *label) {
         return 0;
 }
 
+int mac_selinux_apply_fd(int fd, const char *path, const char *label) {
+
+        assert(fd >= 0);
+
+#if HAVE_SELINUX
+        if (!mac_selinux_use())
+                return 0;
+
+        assert(label);
+
+        if (fsetfilecon(fd, label) < 0)
+                return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
+#endif
+        return 0;
+}
+
 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
 #if HAVE_SELINUX
         _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
index a982289f6aa9912bfd98818339b649f5419e2638..43d22b914fd914494c4076eaa86dd0f0f8bc7c5f 100644 (file)
@@ -28,7 +28,13 @@ static inline int mac_selinux_fix(const char *path, LabelFixFlags flags) {
         return mac_selinux_fix_container(path, path, flags);
 }
 
+int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags);
+static inline int mac_selinux_fix_fd(int fd, const char *path, LabelFixFlags flags) {
+        return mac_selinux_fix_container_fd(fd, path, path, flags);
+}
+
 int mac_selinux_apply(const char *path, const char *label);
+int mac_selinux_apply_fd(int fd, const char *path, const char *label);
 
 int mac_selinux_get_create_label_from_exe(const char *exe, char **label);
 int mac_selinux_get_our_label(char **label);
index 7170eea84c1437cc042c8b6fa6407381415e2489..7749c18c45748e67eec746733ece98d5e00e5f3f 100644 (file)
@@ -128,10 +128,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HAS
 
 int set_consume(Set *s, void *value);
 
-int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS);
-#define set_put_strdup(s, p) _set_put_strdup(s, p  HASHMAP_DEBUG_SRC_ARGS)
-int _set_put_strdupv(Set **s, char **l  HASHMAP_DEBUG_PARAMS);
-#define set_put_strdupv(s, l) _set_put_strdupv(s, l  HASHMAP_DEBUG_SRC_ARGS)
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p  HASHMAP_DEBUG_PARAMS);
+#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p  HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HASHMAP_DEBUG_PARAMS);
+#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l  HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
 
 int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
 
index dd69eaaac2da520d8468179ba936d4dacea6f2b6..718a6953e5b57622c8e26ddf9855e6703b8978e7 100644 (file)
@@ -129,8 +129,5 @@ int socket_address_listen(
         if (p)
                 (void) touch(p);
 
-        r = fd;
-        fd = -1;
-
-        return r;
+        return TAKE_FD(fd);
 }
index cefbda3577b47cadf99461b197ada351f2fe1ac7..bad384a69358be64d52e495d026aedd6e833e68d 100644 (file)
@@ -33,6 +33,12 @@ static inline bool streq_ptr(const char *a, const char *b) {
         return strcmp_ptr(a, b) == 0;
 }
 
+static inline char* strstr_ptr(const char *haystack, const char *needle) {
+        if (!haystack || !needle)
+                return NULL;
+        return strstr(haystack, needle);
+}
+
 static inline const char* strempty(const char *s) {
         return s ?: "";
 }
@@ -53,6 +59,10 @@ static inline const char* true_false(bool b) {
         return b ? "true" : "false";
 }
 
+static inline const char* plus_minus(bool b) {
+        return b ? "+" : "-";
+}
+
 static inline const char* one_zero(bool b) {
         return b ? "1" : "0";
 }
index e4ecf405b7e717609957ae1d27d6fa3b29dff6c4..c5e6dd5f2182f188578d96c208127e6510cb26cd 100644 (file)
@@ -367,7 +367,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
         return (int) n;
 }
 
-char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) {
+char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
         char * const *s;
         char *r, *e;
         size_t n, k, m;
@@ -378,11 +378,17 @@ char *strv_join_prefix(char * const *l, const char *separator, const char *prefi
         k = strlen(separator);
         m = strlen_ptr(prefix);
 
+        if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */
+                assert(k == 1);
+
         n = 0;
         STRV_FOREACH(s, l) {
                 if (s != l)
                         n += k;
-                n += m + strlen(*s);
+
+                bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
+
+                n += m + strlen(*s) * (1 + needs_escaping);
         }
 
         r = new(char, n+1);
@@ -397,7 +403,16 @@ char *strv_join_prefix(char * const *l, const char *separator, const char *prefi
                 if (prefix)
                         e = stpcpy(e, prefix);
 
-                e = stpcpy(e, *s);
+                bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
+
+                if (needs_escaping)
+                        for (size_t i = 0; (*s)[i]; i++) {
+                                if ((*s)[i] == separator[0])
+                                        *(e++) = '\\';
+                                *(e++) = (*s)[i];
+                        }
+                else
+                        e = stpcpy(e, *s);
         }
 
         *e = 0;
@@ -522,6 +537,19 @@ int strv_consume_prepend(char ***l, char *value) {
         return r;
 }
 
+int strv_prepend(char ***l, const char *value) {
+        char *v;
+
+        if (!value)
+                return 0;
+
+        v = strdup(value);
+        if (!v)
+                return -ENOMEM;
+
+        return strv_consume_prepend(l, v);
+}
+
 int strv_extend(char ***l, const char *value) {
         char *v;
 
index 9468edc6a6aca62c540f4d9c0f8ee68410ad58d7..a85c289d7399b03427c274462061a5e6df39c664 100644 (file)
@@ -34,6 +34,7 @@ size_t strv_length(char * const *l) _pure_;
 
 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
 int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
+int strv_prepend(char ***l, const char *value);
 int strv_extend(char ***l, const char *value);
 int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
 int strv_extend_front(char ***l, const char *value);
@@ -62,7 +63,7 @@ char **strv_new_internal(const char *x, ...) _sentinel_;
 char **strv_new_ap(const char *x, va_list ap);
 #define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
 
-#define STRV_IGNORE ((const char *) -1)
+#define STRV_IGNORE ((const char *) POINTER_MAX)
 
 static inline const char* STRV_IFNOTNULL(const char *x) {
         return x ? x : STRV_IGNORE;
@@ -91,9 +92,9 @@ static inline char **strv_split(const char *s, const char *separators) {
  * string in the vector is an empty string. */
 int strv_split_colon_pairs(char ***t, const char *s);
 
-char *strv_join_prefix(char * const *l, const char *separator, const char *prefix);
+char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
 static inline char *strv_join(char * const *l, const char *separator) {
-        return strv_join_prefix(l, separator, NULL);
+        return strv_join_full(l, separator, NULL, false);
 }
 
 char **strv_parse_nulstr(const char *s, size_t l);
index 6cacde90bac6b58333368ed1cf6dfc301c338a17..ac83688531f2530eb27d271a78b19814caa1d1f1 100644 (file)
@@ -1349,7 +1349,7 @@ int vt_release(int fd, bool restore) {
 
 void get_log_colors(int priority, const char **on, const char **off, const char **highlight) {
         /* Note that this will initialize output variables only when there's something to output.
-         * The caller must pre-initalize to "" or NULL as appropriate. */
+         * The caller must pre-initialize to "" or NULL as appropriate. */
 
         if (priority <= LOG_ERR) {
                 if (on)
index cecd5efa604ae07970265e91a02332880646c5aa..6feda5e1559e60f92d137270e14508fbf13b84da 100644 (file)
@@ -63,10 +63,10 @@ typedef enum TimestampStyle {
 
 /* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this
  * to 6. Let's rely on that. */
-#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1)
-#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
-#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
-#define FORMAT_TIMESPAN_MAX 64
+#define FORMAT_TIMESTAMP_MAX (3U+1U+10U+1U+8U+1U+6U+1U+6U+1U)
+#define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */
+#define FORMAT_TIMESTAMP_RELATIVE_MAX 256U
+#define FORMAT_TIMESPAN_MAX 64U
 
 #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
 
index 7c142dd1e66e6521f91a2cf73eb247a755870257..13e2c99e6c22e3e563b5ab448b218ecf83a8892a 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <grp.h>
 #if ENABLE_GSHADOW
-#include <gshadow.h>
+#  include <gshadow.h>
 #endif
 #include <pwd.h>
 #include <shadow.h>
@@ -61,30 +61,6 @@ int take_etc_passwd_lock(const char *root);
 
 #define ETC_PASSWD_LOCK_PATH "/etc/.pwd.lock"
 
-static inline bool uid_is_system(uid_t uid) {
-        return uid <= SYSTEM_UID_MAX;
-}
-
-static inline bool gid_is_system(gid_t gid) {
-        return gid <= SYSTEM_GID_MAX;
-}
-
-static inline bool uid_is_dynamic(uid_t uid) {
-        return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
-}
-
-static inline bool gid_is_dynamic(gid_t gid) {
-        return uid_is_dynamic((uid_t) gid);
-}
-
-static inline bool uid_is_container(uid_t uid) {
-        return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
-}
-
-static inline bool gid_is_container(gid_t gid) {
-        return uid_is_container((uid_t) gid);
-}
-
 /* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
  * NULL is special */
 #define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
index 212b3b7039c42ea64969279ca6c9bf448a01089b..bb908847f5b1f2b056cfb19654a7db9c649d39f3 100644 (file)
@@ -93,6 +93,11 @@ static int detect_vm_device_tree(void) {
                 _cleanup_closedir_ DIR *dir = NULL;
                 struct dirent *dent;
 
+                if (access("/proc/device-tree/ibm,partition-name", F_OK) == 0 &&
+                    access("/proc/device-tree/hmc-managed?", F_OK) == 0 &&
+                    access("/proc/device-tree/chosen/qemu,graphic-width", F_OK) != 0)
+                        return VIRTUALIZATION_POWERVM;
+
                 dir = opendir("/proc/device-tree");
                 if (!dir) {
                         if (errno == ENOENT) {
@@ -499,7 +504,7 @@ int detect_container(void) {
                 goto translate_name;
         }
         if (!IN_SET(r, -ENOENT, 0))
-                return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
+                return log_debug_errno(r, "Failed to read /run/systemd/container-manager: %m");
 
         if (getpid_cached() == 1) {
                 /* If we are PID 1 we can just check our own environment variable, and that's authoritative.
@@ -679,6 +684,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_BHYVE] = "bhyve",
         [VIRTUALIZATION_QNX] = "qnx",
         [VIRTUALIZATION_ACRN] = "acrn",
+        [VIRTUALIZATION_POWERVM] = "powervm",
         [VIRTUALIZATION_VM_OTHER] = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
index 18aa5eff15316f22896b9601b2feced7ebb7c8d3..2f7f7203d2948331be265ee48fca0b2f76862fc4 100644 (file)
@@ -22,6 +22,7 @@ enum {
         VIRTUALIZATION_BHYVE,
         VIRTUALIZATION_QNX,
         VIRTUALIZATION_ACRN,
+        VIRTUALIZATION_POWERVM,
         VIRTUALIZATION_VM_OTHER,
         VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
 
index f464882186fcc7b65e802c7a29ff1c53f61367c8..bb8c7398f048182fb31b7b229f812c4902cb491a 100644 (file)
@@ -1014,24 +1014,25 @@ static int help(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_oom();
 
-        printf("%s  [OPTIONS...] COMMAND ...\n"
-               "\n%sInstall/update/remove the systemd-boot EFI boot manager and list/select entries.%s\n"
-               "\nBoot Loader Commands:\n"
-               "  status              Show status of installed systemd-boot and EFI variables\n"
-               "  install             Install systemd-boot to the ESP and EFI variables\n"
-               "  update              Update systemd-boot in the ESP and EFI variables\n"
-               "  remove              Remove systemd-boot from the ESP and EFI variables\n"
-               "  is-installed        Test whether systemd-boot is installed in the ESP\n"
-               "  random-seed         Initialize random seed in ESP and EFI variables\n"
-               "  systemd-efi-options [STRING]\n"
-               "                      Query or set system options string in EFI variable\n"
+        printf("%1$s  [OPTIONS...] COMMAND ...\n"
+               "\n%5$sControl EFI firmware boot settings and manage boot loader.%6$s\n"
+               "\n%3$sGeneric EFI Firmware/Boot Loader Commands:%4$s\n"
+               "  status              Show status of installed boot loader and EFI variables\n"
                "  reboot-to-firmware [BOOL]\n"
                "                      Query or set reboot-to-firmware EFI flag\n"
-               "\nBoot Loader Entries Commands:\n"
+               "  systemd-efi-options [STRING]\n"
+               "                      Query or set system options string in EFI variable\n"
+               "\n%3$sBoot Loader Specification Commands:%4$s\n"
                "  list                List boot loader entries\n"
                "  set-default ID      Set default boot loader entry\n"
                "  set-oneshot ID      Set default boot loader entry, for next boot only\n"
-               "\nOptions:\n"
+               "\n%3$ssystemd-boot Commands:%4$s\n"
+               "  install             Install systemd-boot to the ESP and EFI variables\n"
+               "  update              Update systemd-boot in the ESP and EFI variables\n"
+               "  remove              Remove systemd-boot from the ESP and EFI variables\n"
+               "  is-installed        Test whether systemd-boot is installed in the ESP\n"
+               "  random-seed         Initialize random seed in ESP and EFI variables\n"
+               "\n%3$sOptions:%4$s\n"
                "  -h --help            Show this help\n"
                "     --version         Print version\n"
                "     --esp-path=PATH   Path to the EFI System Partition (ESP)\n"
@@ -1042,11 +1043,12 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --no-pager        Do not pipe output into a pager\n"
                "     --graceful        Don't fail when the ESP cannot be found or EFI\n"
                "                       variables cannot be written\n"
-               "\nSee the %s for details.\n"
+               "\nSee the %2$s for details.\n"
                , program_invocation_short_name
-               , ansi_highlight()
-               , ansi_normal()
-               , link);
+               , link
+               , ansi_underline(), ansi_normal()
+               , ansi_highlight(), ansi_normal()
+        );
 
         return 0;
 }
@@ -1659,6 +1661,31 @@ static int verb_is_installed(int argc, char *argv[], void *userdata) {
         return EXIT_SUCCESS;
 }
 
+static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) {
+        int r;
+        if (streq(arg1, "@current")) {
+                r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntrySelected", NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
+        } else if (streq(arg1, "@oneshot")) {
+                r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntryOneShot", NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
+        } else if (streq(arg1, "@default")) {
+                r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntryDefault", NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
+        } else {
+                char16_t *encoded = NULL;
+                encoded = utf8_to_utf16(arg1, strlen(arg1));
+                if (!encoded)
+                        return log_oom();
+                *ret_target = encoded;
+                *ret_target_size = char16_strlen(encoded) * 2 + 2;
+        }
+        return 0;
+}
+
 static int verb_set_default(int argc, char *argv[], void *userdata) {
         const char *name;
         int r;
@@ -1691,17 +1718,17 @@ static int verb_set_default(int argc, char *argv[], void *userdata) {
         if (isempty(argv[1])) {
                 r = efi_set_variable(EFI_VENDOR_LOADER, name, NULL, 0);
                 if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to remove EFI variale: %m");
+                        return log_error_errno(r, "Failed to remove EFI variable '%s': %m", name);
         } else {
-                _cleanup_free_ char16_t *encoded = NULL;
+                _cleanup_free_ char16_t *target = NULL;
+                size_t target_size = 0;
 
-                encoded = utf8_to_utf16(argv[1], strlen(argv[1]));
-                if (!encoded)
-                        return log_oom();
-
-                r = efi_set_variable(EFI_VENDOR_LOADER, name, encoded, char16_strlen(encoded) * 2 + 2);
+                r = parse_loader_entry_target_arg(argv[1], &target, &target_size);
+                if (r < 0)
+                        return r;
+                r = efi_set_variable(EFI_VENDOR_LOADER, name, target, target_size);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to update EFI variable: %m");
+                        return log_error_errno(r, "Failed to update EFI variable '%s': %m", name);
         }
 
         return 0;
index 0b712d856f00fa83cd3c848be44597df775ec360..4d87117b00cce9f666474e7278d9792456089a80 100644 (file)
@@ -266,7 +266,7 @@ static EFI_TCG * tcg1_interface_check(void) {
         return tcg;
 }
 
-static EFI_TCG2 * tcg2_interface_check() {
+static EFI_TCG2 * tcg2_interface_check(void) {
         EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
         EFI_STATUS status;
         EFI_TCG2 *tcg;
index 16dca649cf9c929cf7170a55d191d04f0b899fda..446e47411295aa85a11ab3d13eab4a40ceee65d8 100644 (file)
@@ -129,11 +129,11 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) {
                 }
         }
         if (r < 0)
-                return log_error_errno(r, "Failed to set address: %m");
+                return bus_log_address_error(r);
 
         r = sd_bus_start(bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to bus: %m");
+                return bus_log_connect_error(r);
 
         *ret = TAKE_PTR(bus);
 
@@ -1130,14 +1130,13 @@ static int introspect(int argc, char **argv, void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        if (arg_legend) {
+        if (arg_legend)
                 printf("%-*s %-*s %-*s %-*s %s\n",
                        (int) name_width, "NAME",
                        (int) type_width, "TYPE",
                        (int) signature_width, "SIGNATURE",
                        (int) result_width, "RESULT/VALUE",
                        "FLAGS");
-        }
 
         for (j = 0; j < k; j++) {
                 _cleanup_free_ char *ellipsized = NULL;
index 042d83c495ca9e40162fb62b3dfe5767031b352d..0efaf3873ede948449b2d4d3bb343eb0d4e69e68 100644 (file)
@@ -91,6 +91,15 @@ static Group *group_free(Group *g) {
         return mfree(g);
 }
 
+
+static const char *maybe_format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
+        if (arg_raw) {
+               snprintf(buf, l, USEC_FMT, t);
+               return buf;
+        }
+        return format_timespan(buf, l, t, accuracy);
+}
+
 static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
         if (!is_valid)
                 return "-";
@@ -586,7 +595,7 @@ static void display(Hashmap *a) {
         Group **array;
         signed path_columns;
         unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
-        char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)];
+        char buffer[MAX4(21U, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX, DECIMAL_STR_MAX(usec_t))];
 
         assert(a);
 
@@ -605,7 +614,7 @@ static void display(Hashmap *a) {
         for (j = 0; j < n; j++) {
                 unsigned cputlen, pathtlen;
 
-                format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
+                maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
                 cputlen = strlen(buffer);
                 maxtcpu = MAX(maxtcpu, cputlen);
 
@@ -674,7 +683,7 @@ static void display(Hashmap *a) {
                         else
                                 fputs("      -", stdout);
                 } else
-                        printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
+                        printf(" %*s", maxtcpu, maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
 
                 printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
                 printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));
index b0d43a3ef40ace0f3010cae6b95804855b82e123..9c0dca1b3a78c38fa82340a120e9a23fbb8623f1 100644 (file)
@@ -540,10 +540,8 @@ static void automount_trigger_notify(Unit *u, Unit *other) {
                    MOUNT_MOUNTED, MOUNT_REMOUNTING,
                    MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
                    MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
-                   MOUNT_FAILED)) {
-
+                   MOUNT_FAILED))
                 (void) automount_send_ready(a, a->expire_tokens, -ENODEV);
-        }
 
         if (MOUNT(other)->state == MOUNT_DEAD)
                 (void) automount_send_ready(a, a->expire_tokens, 0);
index 211e4a5945f02f65309b5fdc03f3979e77becbe7..1958c1be2b9f24124c047d4463300b9911a15ccc 100644 (file)
@@ -128,6 +128,9 @@ void cgroup_context_init(CGroupContext *c) {
                 .startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID,
 
                 .tasks_max = TASKS_MAX_UNSET,
+
+                .moom_swap = MANAGED_OOM_AUTO,
+                .moom_mem_pressure = MANAGED_OOM_AUTO,
         };
 }
 
@@ -411,7 +414,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 "%sTasksMax: %" PRIu64 "\n"
                 "%sDevicePolicy: %s\n"
                 "%sDisableControllers: %s\n"
-                "%sDelegate: %s\n",
+                "%sDelegate: %s\n"
+                "%sManagedOOMSwap: %s\n"
+                "%sManagedOOMMemoryPressure: %s\n"
+                "%sManagedOOMMemoryPressureLimitPercent: %d%%\n",
                 prefix, yes_no(c->cpu_accounting),
                 prefix, yes_no(c->io_accounting),
                 prefix, yes_no(c->blockio_accounting),
@@ -441,7 +447,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 prefix, tasks_max_resolve(&c->tasks_max),
                 prefix, cgroup_device_policy_to_string(c->device_policy),
                 prefix, strempty(disable_controllers_str),
-                prefix, yes_no(c->delegate));
+                prefix, yes_no(c->delegate),
+                prefix, managed_oom_mode_to_string(c->moom_swap),
+                prefix, managed_oom_mode_to_string(c->moom_mem_pressure),
+                prefix, c->moom_mem_pressure_limit);
 
         if (c->delegate) {
                 _cleanup_free_ char *t = NULL;
@@ -2672,6 +2681,47 @@ static void unit_remove_from_cgroup_empty_queue(Unit *u) {
         u->in_cgroup_empty_queue = false;
 }
 
+int unit_check_oomd_kill(Unit *u) {
+        _cleanup_free_ char *value = NULL;
+        bool increased;
+        uint64_t n = 0;
+        int r;
+
+        if (!u->cgroup_path)
+                return 0;
+
+        r = cg_all_unified();
+        if (r < 0)
+                return log_unit_debug_errno(u, r, "Couldn't determine whether we are in all unified mode: %m");
+        else if (r == 0)
+                return 0;
+
+        r = cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "user.systemd_oomd_kill", &value);
+        if (r < 0 && r != -ENODATA)
+                return r;
+
+        if (!isempty(value)) {
+                 r = safe_atou64(value, &n);
+                 if (r < 0)
+                         return r;
+        }
+
+        increased = n > u->managed_oom_kill_last;
+        u->managed_oom_kill_last = n;
+
+        if (!increased)
+                return 0;
+
+        if (n > 0)
+                log_struct(LOG_NOTICE,
+                           "MESSAGE_ID=" SD_MESSAGE_UNIT_OOMD_KILL_STR,
+                           LOG_UNIT_ID(u),
+                           LOG_UNIT_INVOCATION_ID(u),
+                           LOG_UNIT_MESSAGE(u, "systemd-oomd killed %"PRIu64" process(es) in this unit.", n));
+
+        return 1;
+}
+
 int unit_check_oom(Unit *u) {
         _cleanup_free_ char *oom_kill = NULL;
         bool increased;
index 9ac5c8bfc0b993a0a9567335eceeff777c2ce1e4..881b3f3dfe88ac053b80cf791e89b9465fb9bd2a 100644 (file)
@@ -159,6 +159,11 @@ struct CGroupContext {
 
         /* Common */
         TasksMax tasks_max;
+
+        /* Settings for systemd-oomd */
+        ManagedOOMMode moom_swap;
+        ManagedOOMMode moom_mem_pressure;
+        int moom_mem_pressure_limit;
 };
 
 /* Used when querying IP accounting data */
@@ -224,6 +229,7 @@ int unit_watch_cgroup(Unit *u);
 int unit_watch_cgroup_memory(Unit *u);
 
 void unit_add_to_cgroup_empty_queue(Unit *u);
+int unit_check_oomd_kill(Unit *u);
 int unit_check_oom(Unit *u);
 
 int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path);
index 4bb262bd93d24cfcd426ff7cebb9f405a80049d6..411c8557d976c7078880733bc5a0ddebad305a6e 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "core-varlink.h"
 #include "mkdir.h"
+#include "strv.h"
 #include "user-util.h"
 #include "varlink.h"
 
@@ -15,6 +16,11 @@ typedef struct LookupParameters {
         const char *service;
 } LookupParameters;
 
+static const char* const managed_oom_mode_properties[] = {
+        "ManagedOOMSwap",
+        "ManagedOOMMemoryPressure",
+};
+
 static int build_user_json(const char *user_name, uid_t uid, JsonVariant **ret) {
         assert(user_name);
         assert(uid_is_valid(uid));
@@ -45,6 +51,147 @@ static bool user_match_lookup_parameters(LookupParameters *p, const char *name,
         return true;
 }
 
+static int build_managed_oom_json_array_element(Unit *u, const char *property, JsonVariant **ret_v) {
+        bool use_limit = false;
+        CGroupContext *c;
+        const char *mode;
+
+        assert(u);
+        assert(property);
+        assert(ret_v);
+
+        if (!UNIT_VTABLE(u)->can_set_managed_oom)
+                return -EOPNOTSUPP;
+
+        c = unit_get_cgroup_context(u);
+        if (!c)
+                return -EINVAL;
+
+        if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
+                /* systemd-oomd should always treat inactive units as though they didn't enable any action since they
+                 * should not have a valid cgroup */
+                mode = managed_oom_mode_to_string(MANAGED_OOM_AUTO);
+        else if (streq(property, "ManagedOOMSwap"))
+                mode = managed_oom_mode_to_string(c->moom_swap);
+        else if (streq(property, "ManagedOOMMemoryPressure")) {
+                mode = managed_oom_mode_to_string(c->moom_mem_pressure);
+                use_limit = true;
+        } else
+                return -EINVAL;
+
+        return json_build(ret_v, JSON_BUILD_OBJECT(
+                                 JSON_BUILD_PAIR("mode", JSON_BUILD_STRING(mode)),
+                                 JSON_BUILD_PAIR("path", JSON_BUILD_STRING(u->cgroup_path)),
+                                 JSON_BUILD_PAIR("property", JSON_BUILD_STRING(property)),
+                                 JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit))));
+}
+
+int manager_varlink_send_managed_oom_update(Unit *u) {
+        _cleanup_(json_variant_unrefp) JsonVariant *arr = NULL, *v = NULL;
+        CGroupContext *c;
+        int r;
+
+        assert(u);
+
+        if (!UNIT_VTABLE(u)->can_set_managed_oom || !u->manager || !u->manager->managed_oom_varlink_request || !u->cgroup_path)
+                return 0;
+
+        c = unit_get_cgroup_context(u);
+        if (!c)
+                return 0;
+
+        r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY);
+        if (r < 0)
+                return r;
+
+        for (size_t i = 0; i < ELEMENTSOF(managed_oom_mode_properties); i++) {
+                _cleanup_(json_variant_unrefp) JsonVariant *e = NULL;
+
+                r = build_managed_oom_json_array_element(u, managed_oom_mode_properties[i], &e);
+                if (r < 0)
+                        return r;
+
+                r = json_variant_append_array(&arr, e);
+                if (r < 0)
+                        return r;
+        }
+
+        r = json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("cgroups", JSON_BUILD_VARIANT(arr))));
+        if (r < 0)
+                return r;
+
+        return varlink_notify(u->manager->managed_oom_varlink_request, v);
+}
+
+static int vl_method_subscribe_managed_oom_cgroups(
+                Varlink *link,
+                JsonVariant *parameters,
+                VarlinkMethodFlags flags,
+                void *userdata) {
+        static const UnitType supported_unit_types[] = { UNIT_SLICE, UNIT_SERVICE, UNIT_SCOPE };
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *arr = NULL;
+        Manager *m = userdata;
+        int r;
+
+        assert(link);
+        assert(m);
+
+        if (json_variant_elements(parameters) > 0)
+                return varlink_error_invalid_parameter(link, parameters);
+
+        /* We only take one subscriber for this method so return an error if there's already an existing one.
+         * This shouldn't happen since systemd-oomd is the only client of this method. */
+        if (FLAGS_SET(flags, VARLINK_METHOD_MORE) && m->managed_oom_varlink_request)
+                return varlink_error(m->managed_oom_varlink_request, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL);
+
+        r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY);
+        if (r < 0)
+                return r;
+
+        for (size_t i = 0; i < ELEMENTSOF(supported_unit_types); i++) {
+                Unit *u;
+
+                LIST_FOREACH(units_by_type, u, m->units_by_type[supported_unit_types[i]]) {
+                        CGroupContext *c;
+
+                        if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
+                                continue;
+
+                        c = unit_get_cgroup_context(u);
+                        if (!c)
+                                continue;
+
+                        for (size_t j = 0; j < ELEMENTSOF(managed_oom_mode_properties); j++) {
+                                _cleanup_(json_variant_unrefp) JsonVariant *e = NULL;
+
+                                /* For the initial varlink call we only care about units that enabled (i.e. mode is not
+                                 * set to "auto") oomd properties. */
+                                if (!(streq(managed_oom_mode_properties[j], "ManagedOOMSwap") && c->moom_swap == MANAGED_OOM_KILL) &&
+                                    !(streq(managed_oom_mode_properties[j], "ManagedOOMMemoryPressure") && c->moom_mem_pressure == MANAGED_OOM_KILL))
+                                        continue;
+
+                                r = build_managed_oom_json_array_element(u, managed_oom_mode_properties[j], &e);
+                                if (r < 0)
+                                        return r;
+
+                                r = json_variant_append_array(&arr, e);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        }
+
+        r = json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("cgroups", JSON_BUILD_VARIANT(arr))));
+        if (r < 0)
+                return r;
+
+        if (!FLAGS_SET(flags, VARLINK_METHOD_MORE))
+                return varlink_reply(link, v);
+
+        m->managed_oom_varlink_request = varlink_ref(link);
+        return varlink_notify(m->managed_oom_varlink_request, v);
+}
+
 static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
 
         static const JsonDispatch dispatch_table[] = {
@@ -262,6 +409,17 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var
         return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
 }
 
+static void vl_disconnect(VarlinkServer *s, Varlink *link, void *userdata) {
+        Manager *m = userdata;
+
+        assert(m);
+        assert(s);
+        assert(link);
+
+        if (link == m->managed_oom_varlink_request)
+                m->managed_oom_varlink_request = varlink_unref(link);
+}
+
 int manager_varlink_init(Manager *m) {
         _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
         int r;
@@ -284,16 +442,25 @@ int manager_varlink_init(Manager *m) {
                         s,
                         "io.systemd.UserDatabase.GetUserRecord",  vl_method_get_user_record,
                         "io.systemd.UserDatabase.GetGroupRecord", vl_method_get_group_record,
-                        "io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships);
+                        "io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships,
+                        "io.systemd.ManagedOOM.SubscribeManagedOOMCGroups",  vl_method_subscribe_managed_oom_cgroups);
         if (r < 0)
                 return log_error_errno(r, "Failed to register varlink methods: %m");
 
+        r = varlink_server_bind_disconnect(s, vl_disconnect);
+        if (r < 0)
+                return log_error_errno(r, "Failed to register varlink disconnect handler: %m");
+
         if (!MANAGER_IS_TEST_RUN(m)) {
                 (void) mkdir_p_label("/run/systemd/userdb", 0755);
 
                 r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
                 if (r < 0)
                         return log_error_errno(r, "Failed to bind to varlink socket: %m");
+
+                r = varlink_server_listen_address(s, VARLINK_ADDR_PATH_MANAGED_OOM, 0666);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to bind to varlink socket: %m");
         }
 
         r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
@@ -307,5 +474,9 @@ int manager_varlink_init(Manager *m) {
 void manager_varlink_done(Manager *m) {
         assert(m);
 
+        /* Send the final message if we still have a subscribe request open. */
+        if (m->managed_oom_varlink_request)
+                m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request);
+
         m->varlink_server = varlink_server_unref(m->varlink_server);
 }
index 89818e2766caa318cb17f5103509ae12fe7ac619..0b191ae6c44d2c5419bd92cf3115135f6071454c 100644 (file)
@@ -5,3 +5,8 @@
 
 int manager_varlink_init(Manager *m);
 void manager_varlink_done(Manager *m);
+
+/* The manager is expected to send an update to systemd-oomd if one of the following occurs:
+ * - The value of ManagedOOM*= properties change
+ * - A unit with ManagedOOM*= properties changes unit active state */
+int manager_varlink_send_managed_oom_update(Unit *u);
index b7d2e32639a51699b5df2404c3260e73bb672a9c..584d974f1a2332863a40857a85578b45679f45b5 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-get-properties.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
+#include "core-varlink.h"
 #include "dbus-cgroup.h"
 #include "dbus-util.h"
 #include "errno-util.h"
@@ -19,6 +20,7 @@
 BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve);
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_mode, managed_oom_mode, ManagedOOMMode);
 
 static int property_get_cgroup_mask(
                 sd_bus *bus,
@@ -391,6 +393,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("IPIngressFilterPath", "as", NULL, offsetof(CGroupContext, ip_filters_ingress), 0),
         SD_BUS_PROPERTY("IPEgressFilterPath", "as", NULL, offsetof(CGroupContext, ip_filters_egress), 0),
         SD_BUS_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0),
+        SD_BUS_PROPERTY("ManagedOOMSwap", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_swap), 0),
+        SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0),
+        SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPercent", "s", bus_property_get_percent, offsetof(CGroupContext, moom_mem_pressure_limit), 0),
         SD_BUS_VTABLE_END
 };
 
@@ -1500,9 +1505,9 @@ int bus_cgroup_set_property(
                                         LIST_PREPEND(device_allow, c->device_allow, a);
                                 }
 
-                                a->r = !!strchr(rwm, 'r');
-                                a->w = !!strchr(rwm, 'w');
-                                a->m = !!strchr(rwm, 'm');
+                                a->r = strchr(rwm, 'r');
+                                a->w = strchr(rwm, 'w');
+                                a->m = strchr(rwm, 'm');
                         }
 
                         n++;
@@ -1667,6 +1672,45 @@ int bus_cgroup_set_property(
                 return 1;
         }
 
+        if (STR_IN_SET(name, "ManagedOOMSwap", "ManagedOOMMemoryPressure")) {
+                ManagedOOMMode *cgroup_mode = streq(name, "ManagedOOMSwap") ? &c->moom_swap : &c->moom_mem_pressure;
+                ManagedOOMMode m;
+                const char *mode;
+
+                if (!UNIT_VTABLE(u)->can_set_managed_oom)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name);
+
+                r = sd_bus_message_read(message, "s", &mode);
+                if (r < 0)
+                        return r;
+
+                m = managed_oom_mode_from_string(mode);
+                if (m < 0)
+                        return -EINVAL;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        *cgroup_mode = m;
+                        unit_write_settingf(u, flags, name, "%s=%s", name, mode);
+                }
+
+                (void) manager_varlink_send_managed_oom_update(u);
+                return 1;
+        }
+
+        if (streq(name, "ManagedOOMMemoryPressureLimitPercent")) {
+                if (!UNIT_VTABLE(u)->can_set_managed_oom)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name);
+
+                r = bus_set_transient_percent(u, name, &c->moom_mem_pressure_limit, message, flags, error);
+                if (r < 0)
+                        return r;
+
+                if (c->moom_mem_pressure == MANAGED_OOM_KILL)
+                        (void) manager_varlink_send_managed_oom_update(u);
+
+                return 1;
+        }
+
         if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
                 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
 
index 753b91d511a7ec3a59fc59049f0acf8f2ffeef38..488af98cd325b69f30619547a1410771748508db 100644 (file)
@@ -53,6 +53,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_home, protect_home, Pro
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_system, protect_system, ProtectSystem);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_personality, personality, unsigned long);
 static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
+static BUS_DEFINE_PROPERTY_GET(property_get_mount_apivfs, "b", ExecContext, exec_context_get_effective_mount_apivfs);
 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_class, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_CLASS);
 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_DATA);
 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
@@ -1143,7 +1144,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TemporaryFileSystem", "a(ss)", property_get_temporary_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("MountAPIVFS", "b", property_get_mount_apivfs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ProtectProc", "s", property_get_protect_proc, offsetof(ExecContext, protect_proc), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1805,9 +1806,6 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "ProtectControlGroups"))
                 return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error);
 
-        if (streq(name, "MountAPIVFS"))
-                return bus_set_transient_bool(u, name, &c->mount_apivfs, message, flags, error);
-
         if (streq(name, "CPUSchedulingResetOnFork"))
                 return bus_set_transient_bool(u, name, &c->cpu_sched_reset_on_fork, message, flags, error);
 
@@ -2635,6 +2633,20 @@ int bus_exec_context_set_transient_property(
 
                 return 1;
 
+        } else if (streq(name, "MountAPIVFS")) {
+                bool b;
+
+                r = bus_set_transient_bool(u, name, &b, message, flags, error);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        c->mount_apivfs = b;
+                        c->mount_apivfs_set = true;
+                }
+
+                return 1;
+
         } else if (streq(name, "WorkingDirectory")) {
                 const char *s;
                 bool missing_ok;
index 951450e53daa418bde5406b806b6fb9e393424df..f534001a9c2c252eb641785104fe6c2f8357e561 100644 (file)
@@ -91,6 +91,35 @@ int bus_set_transient_bool(
         return 1;
 }
 
+int bus_set_transient_percent(
+                Unit *u,
+                const char *name,
+                int *p,
+                sd_bus_message *message,
+                UnitWriteFlags flags,
+                sd_bus_error *error) {
+
+        const char *v;
+        int r;
+
+        assert(p);
+
+        r = sd_bus_message_read(message, "s", &v);
+        if (r < 0)
+                return r;
+
+        r = parse_percent(v);
+        if (r < 0)
+                return r;
+
+        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                *p = r;
+                unit_write_settingf(u, flags, name, "%s=%d%%", name, r);
+        }
+
+        return 1;
+}
+
 int bus_set_transient_usec_internal(
                 Unit *u,
                 const char *name,
index 654ceb527950600a6adbdfe2bd572909d3b57571..7781a425befe5c0f271925d23f22b1fc09027d6a 100644 (file)
@@ -240,6 +240,7 @@ int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_m
 int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+int bus_set_transient_percent(Unit *u, const char *name, int *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_usec_internal(Unit *u, const char *name, usec_t *p, bool fix_0, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 static inline int bus_set_transient_usec(Unit *u, const char *name, usec_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error) {
         return bus_set_transient_usec_internal(u, name, p, false, message, flags, error);
index 595b009cd935244cb33190e879617af1c7371d49..134c6ee5bbb3c1f68aeeba7a4c2b7d2206d646a4 100644 (file)
@@ -894,6 +894,29 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
         }
 }
 
+static int device_remove_old(Manager *m, sd_device *dev) {
+        _cleanup_free_ char *syspath_old = NULL, *e = NULL;
+        const char *devpath_old;
+        int r;
+
+        r = sd_device_get_property_value(dev, "DEVPATH_OLD", &devpath_old);
+        if (r < 0) {
+                log_device_debug_errno(dev, r, "Failed to get DEVPATH_OLD= property on 'move' uevent, ignoring: %m");
+                return 0;
+        }
+
+        syspath_old = path_join("/sys", devpath_old);
+        if (!syspath_old)
+                return log_oom();
+
+        r = unit_name_from_path(syspath_old, ".device", &e);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to generate unit name from old device path: %m");
+
+        device_update_found_by_sysfs(m, syspath_old, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP);
+        return 0;
+}
+
 static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
         Manager *m = userdata;
         DeviceAction action;
@@ -918,6 +941,9 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
         if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_REMOVE, DEVICE_ACTION_MOVE))
                 device_propagate_reload_by_sysfs(m, sysfs);
 
+        if (action == DEVICE_ACTION_MOVE)
+                (void) device_remove_old(m, dev);
+
         /* A change event can signal that a device is becoming ready, in particular if the device is using
          * the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for
          * change events */
index be386df12bc82b8ecde95b537f912223f2574cb1..8388d53dd12067501a7956296640c5f3d1f8e615 100644 (file)
@@ -19,6 +19,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "user-record.h"
 #include "user-util.h"
 
 /* Takes a value generated randomly or by hashing and turns it into a UID in the right range */
index 44f30cb6343450ac04d082d671c0d5f74b2d060b..98e54acf77efa03ef08b71354cb4c5dfe7828c09 100644 (file)
@@ -1927,7 +1927,7 @@ static int build_environment(
                 if (!pre)
                         return -ENOMEM;
 
-                joined = strv_join_prefix(c->directories[t].paths, ":", pre);
+                joined = strv_join_full(c->directories[t].paths, ":", pre, true);
                 if (!joined)
                         return -ENOMEM;
 
@@ -2027,7 +2027,7 @@ static bool exec_needs_mount_namespace(
                 return true;
 
         if (context->root_directory) {
-                if (context->mount_apivfs)
+                if (exec_context_get_effective_mount_apivfs(context))
                         return true;
 
                 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
@@ -2983,7 +2983,7 @@ static int compile_bind_mounts(
                         continue;
 
                 if (exec_directory_is_private(context, t) &&
-                    !(context->root_directory || context->root_image)) {
+                    !exec_context_with_rootfs(context)) {
                         char *private_root;
 
                         /* So this is for a dynamic user, and we need to make sure the process can access its own
@@ -3014,7 +3014,7 @@ static int compile_bind_mounts(
                         }
 
                         if (exec_directory_is_private(context, t) &&
-                            (context->root_directory || context->root_image))
+                            exec_context_with_rootfs(context))
                                 /* When RootDirectory= or RootImage= are set, then the symbolic link to the private
                                  * directory is not created on the root directory. So, let's bind-mount the directory
                                  * on the 'non-private' place. */
@@ -3147,7 +3147,7 @@ static int apply_mount_namespace(
                         .protect_kernel_modules = context->protect_kernel_modules,
                         .protect_kernel_logs = context->protect_kernel_logs,
                         .protect_hostname = context->protect_hostname,
-                        .mount_apivfs = context->mount_apivfs,
+                        .mount_apivfs = exec_context_get_effective_mount_apivfs(context),
                         .private_mounts = context->private_mounts,
                         .protect_home = context->protect_home,
                         .protect_system = context->protect_system,
@@ -3245,10 +3245,8 @@ static int apply_working_directory(
 
                 wd = home;
 
-        } else if (context->working_directory)
-                wd = context->working_directory;
-        else
-                wd = "/";
+        } else
+                wd = empty_to_root(context->working_directory);
 
         if (params->flags & EXEC_APPLY_CHROOT)
                 d = wd;
@@ -5171,8 +5169,8 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                 "%sProtectProc: %s\n"
                 "%sProcSubset: %s\n",
                 prefix, c->umask,
-                prefix, c->working_directory ? c->working_directory : "/",
-                prefix, c->root_directory ? c->root_directory : "/",
+                prefix, empty_to_root(c->working_directory),
+                prefix, empty_to_root(c->root_directory),
                 prefix, yes_no(c->non_blocking),
                 prefix, yes_no(c->private_tmp),
                 prefix, yes_no(c->private_devices),
@@ -5185,7 +5183,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                 prefix, yes_no(c->private_users),
                 prefix, protect_home_to_string(c->protect_home),
                 prefix, protect_system_to_string(c->protect_system),
-                prefix, yes_no(c->mount_apivfs),
+                prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
                 prefix, yes_no(c->ignore_sigpipe),
                 prefix, yes_no(c->memory_deny_write_execute),
                 prefix, yes_no(c->restrict_realtime),
@@ -5650,6 +5648,20 @@ int exec_context_get_effective_ioprio(const ExecContext *c) {
         return p;
 }
 
+bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
+        assert(c);
+
+        /* Explicit setting wins */
+        if (c->mount_apivfs_set)
+                return c->mount_apivfs;
+
+        /* Default to "yes" if root directory or image are specified */
+        if (exec_context_with_rootfs(c))
+                return true;
+
+        return false;
+}
+
 void exec_context_free_log_extra_fields(ExecContext *c) {
         assert(c);
 
@@ -5760,11 +5772,10 @@ void exec_status_start(ExecStatus *s, pid_t pid) {
 void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
         assert(s);
 
-        if (s->pid != pid) {
+        if (s->pid != pid)
                 *s = (ExecStatus) {
                         .pid = pid,
                 };
-        }
 
         dual_timestamp_get(&s->exit_timestamp);
 
@@ -6057,7 +6068,12 @@ static int exec_runtime_add(
         return 0;
 }
 
-static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
+static int exec_runtime_make(
+                Manager *m,
+                const ExecContext *c,
+                const char *id,
+                ExecRuntime **ret) {
+
         _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
         _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
         int r;
@@ -6067,8 +6083,10 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
         assert(id);
 
         /* It is not necessary to create ExecRuntime object. */
-        if (!c->private_network && !c->private_tmp && !c->network_namespace_path)
+        if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
+                *ret = NULL;
                 return 0;
+        }
 
         if (c->private_tmp &&
             !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
@@ -6104,14 +6122,20 @@ int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool
                 /* We already have a ExecRuntime object, let's increase the ref count and reuse it */
                 goto ref;
 
-        if (!create)
+        if (!create) {
+                *ret = NULL;
                 return 0;
+        }
 
         /* If not found, then create a new object. */
         r = exec_runtime_make(m, c, id, &rt);
-        if (r <= 0)
-                /* When r == 0, it is not necessary to create ExecRuntime object. */
+        if (r < 0)
                 return r;
+        if (r == 0) {
+                /* When r == 0, it is not necessary to create ExecRuntime object. */
+                *ret = NULL;
+                return 0;
+        }
 
 ref:
         /* increment reference counter. */
@@ -6337,7 +6361,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
                 r = safe_atoi(buf, &fdpair[1]);
                 if (r < 0)
                         return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
-                if (!fdset_contains(fds, fdpair[0]))
+                if (!fdset_contains(fds, fdpair[1]))
                         return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
                                                "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
                 fdpair[1] = fdset_remove(fds, fdpair[1]);
index 02a2c8d1e71f3f59ef68de3969e7c096188e9280..12ea849e1cd5762f8a51cca72ac35d18d9300c85 100644 (file)
@@ -23,6 +23,7 @@ typedef struct Manager Manager;
 #include "namespace.h"
 #include "nsflags.h"
 #include "numa-util.h"
+#include "path-util.h"
 #include "time-util.h"
 
 #define EXEC_STDIN_DATA_MAX (64U*1024U*1024U)
@@ -86,7 +87,7 @@ struct ExecStatus {
         dual_timestamp exit_timestamp;
         pid_t pid;
         int code;     /* as in siginfo_t::si_code */
-        int status;   /* as in sigingo_t::si_status */
+        int status;   /* as in siginfo_t::si_status */
 };
 
 /* Stores information about commands we execute. Covers both configuration settings as well as runtime data. */
@@ -174,6 +175,7 @@ struct ExecContext {
         bool nice_set:1;
         bool ioprio_set:1;
         bool cpu_sched_set:1;
+        bool mount_apivfs_set:1;
 
         /* This is not exposed to the user but available internally. We need it to make sure that whenever we
          * spawn /usr/bin/mount it is run in the same process group as us so that the autofs logic detects
@@ -324,6 +326,14 @@ static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
         return (c->restrict_namespaces & NAMESPACE_FLAGS_ALL) != NAMESPACE_FLAGS_ALL;
 }
 
+static inline bool exec_context_with_rootfs(const ExecContext *c) {
+        assert(c);
+
+        /* Checks if RootDirectory= or RootImage= are used */
+
+        return !empty_or_root(c->root_directory) || c->root_image;
+}
+
 typedef enum ExecFlags {
         EXEC_APPLY_SANDBOXING  = 1 << 0,
         EXEC_APPLY_CHROOT      = 1 << 1,
@@ -409,6 +419,7 @@ bool exec_context_may_touch_console(const ExecContext *c);
 bool exec_context_maintains_privileges(const ExecContext *c);
 
 int exec_context_get_effective_ioprio(const ExecContext *c);
+bool exec_context_get_effective_mount_apivfs(const ExecContext *c);
 
 void exec_context_free_log_extra_fields(ExecContext *c);
 
index c60d565eb49efb87a9bd8a67f61535c0b3c2dc72..b5ccf62ae09124bc4dbc41888dddc6d8a5447d18 100644 (file)
@@ -20,485 +20,488 @@ struct ConfigPerfItem;
 %%
 m4_dnl Define the context options only once
 m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
-`$1.WorkingDirectory,            config_parse_working_directory,     0,                             offsetof($1, exec_context)
-$1.RootDirectory,                config_parse_unit_path_printf,      true,                          offsetof($1, exec_context.root_directory)
-$1.RootImage,                    config_parse_unit_path_printf,      true,                          offsetof($1, exec_context.root_image)
-$1.RootImageOptions,             config_parse_root_image_options,    0,                             offsetof($1, exec_context)
-$1.RootHash,                     config_parse_exec_root_hash,        0,                             offsetof($1, exec_context)
-$1.RootHashSignature,            config_parse_exec_root_hash_sig,    0,                             offsetof($1, exec_context)
-$1.RootVerity,                   config_parse_unit_path_printf,      true,                          offsetof($1, exec_context.root_verity)
-$1.MountImages,                  config_parse_mount_images,          0,                             offsetof($1, exec_context)
-$1.User,                         config_parse_user_group_compat,     0,                             offsetof($1, exec_context.user)
-$1.Group,                        config_parse_user_group_compat,     0,                             offsetof($1, exec_context.group)
-$1.SupplementaryGroups,          config_parse_user_group_strv_compat, 0,                            offsetof($1, exec_context.supplementary_groups)
-$1.Nice,                         config_parse_exec_nice,             0,                             offsetof($1, exec_context)
-$1.OOMScoreAdjust,               config_parse_exec_oom_score_adjust, 0,                             offsetof($1, exec_context)
-$1.CoredumpFilter,               config_parse_exec_coredump_filter,  0,                             offsetof($1, exec_context)
-$1.IOSchedulingClass,            config_parse_exec_io_class,         0,                             offsetof($1, exec_context)
-$1.IOSchedulingPriority,         config_parse_exec_io_priority,      0,                             offsetof($1, exec_context)
-$1.CPUSchedulingPolicy,          config_parse_exec_cpu_sched_policy, 0,                             offsetof($1, exec_context)
-$1.CPUSchedulingPriority,        config_parse_exec_cpu_sched_prio,   0,                             offsetof($1, exec_context)
-$1.CPUSchedulingResetOnFork,     config_parse_bool,                  0,                             offsetof($1, exec_context.cpu_sched_reset_on_fork)
-$1.CPUAffinity,                  config_parse_exec_cpu_affinity,     0,                             offsetof($1, exec_context)
-$1.NUMAPolicy,                   config_parse_numa_policy,           0,                             offsetof($1, exec_context.numa_policy.type)
-$1.NUMAMask,                     config_parse_numa_mask,             0,                             offsetof($1, exec_context.numa_policy)
-$1.UMask,                        config_parse_mode,                  0,                             offsetof($1, exec_context.umask)
-$1.Environment,                  config_parse_environ,               0,                             offsetof($1, exec_context.environment)
-$1.EnvironmentFile,              config_parse_unit_env_file,         0,                             offsetof($1, exec_context.environment_files)
-$1.PassEnvironment,              config_parse_pass_environ,          0,                             offsetof($1, exec_context.pass_environment)
-$1.UnsetEnvironment,             config_parse_unset_environ,         0,                             offsetof($1, exec_context.unset_environment)
-$1.DynamicUser,                  config_parse_bool,                  true,                          offsetof($1, exec_context.dynamic_user)
-$1.RemoveIPC,                    config_parse_bool,                  0,                             offsetof($1, exec_context.remove_ipc)
-$1.StandardInput,                config_parse_exec_input,            0,                             offsetof($1, exec_context)
-$1.StandardOutput,               config_parse_exec_output,           0,                             offsetof($1, exec_context)
-$1.StandardError,                config_parse_exec_output,           0,                             offsetof($1, exec_context)
-$1.StandardInputText,            config_parse_exec_input_text,       0,                             offsetof($1, exec_context)
-$1.StandardInputData,            config_parse_exec_input_data,       0,                             offsetof($1, exec_context)
-$1.TTYPath,                      config_parse_unit_path_printf,      0,                             offsetof($1, exec_context.tty_path)
-$1.TTYReset,                     config_parse_bool,                  0,                             offsetof($1, exec_context.tty_reset)
-$1.TTYVHangup,                   config_parse_bool,                  0,                             offsetof($1, exec_context.tty_vhangup)
-$1.TTYVTDisallocate,             config_parse_bool,                  0,                             offsetof($1, exec_context.tty_vt_disallocate)
-$1.SyslogIdentifier,             config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.syslog_identifier)
-$1.SyslogFacility,               config_parse_log_facility,          0,                             offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevel,                  config_parse_log_level,             0,                             offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevelPrefix,            config_parse_bool,                  0,                             offsetof($1, exec_context.syslog_level_prefix)
-$1.LogLevelMax,                  config_parse_log_level,             0,                             offsetof($1, exec_context.log_level_max)
-$1.LogRateLimitIntervalSec,      config_parse_sec,                   0,                             offsetof($1, exec_context.log_ratelimit_interval_usec)
-$1.LogRateLimitBurst,            config_parse_unsigned,              0,                             offsetof($1, exec_context.log_ratelimit_burst)
-$1.LogExtraFields,               config_parse_log_extra_fields,      0,                             offsetof($1, exec_context)
-$1.Capabilities,                 config_parse_warn_compat,           DISABLED_LEGACY,               offsetof($1, exec_context)
-$1.SecureBits,                   config_parse_exec_secure_bits,      0,                             offsetof($1, exec_context.secure_bits)
-$1.CapabilityBoundingSet,        config_parse_capability_set,        0,                             offsetof($1, exec_context.capability_bounding_set)
-$1.AmbientCapabilities,          config_parse_capability_set,        0,                             offsetof($1, exec_context.capability_ambient_set)
-$1.TimerSlackNSec,               config_parse_nsec,                  0,                             offsetof($1, exec_context.timer_slack_nsec)
-$1.NoNewPrivileges,              config_parse_bool,                  0,                             offsetof($1, exec_context.no_new_privileges)
-$1.KeyringMode,                  config_parse_exec_keyring_mode,     0,                             offsetof($1, exec_context.keyring_mode)
-$1.ProtectProc,                  config_parse_protect_proc,          0,                             offsetof($1, exec_context.protect_proc)
-$1.ProcSubset,                   config_parse_proc_subset,           0,                             offsetof($1, exec_context.proc_subset)
+`$1.WorkingDirectory,                    config_parse_working_directory,              0,                                  offsetof($1, exec_context)
+$1.RootDirectory,                        config_parse_unit_path_printf,               true,                               offsetof($1, exec_context.root_directory)
+$1.RootImage,                            config_parse_unit_path_printf,               true,                               offsetof($1, exec_context.root_image)
+$1.RootImageOptions,                     config_parse_root_image_options,             0,                                  offsetof($1, exec_context)
+$1.RootHash,                             config_parse_exec_root_hash,                 0,                                  offsetof($1, exec_context)
+$1.RootHashSignature,                    config_parse_exec_root_hash_sig,             0,                                  offsetof($1, exec_context)
+$1.RootVerity,                           config_parse_unit_path_printf,               true,                               offsetof($1, exec_context.root_verity)
+$1.MountImages,                          config_parse_mount_images,                   0,                                  offsetof($1, exec_context)
+$1.User,                                 config_parse_user_group_compat,              0,                                  offsetof($1, exec_context.user)
+$1.Group,                                config_parse_user_group_compat,              0,                                  offsetof($1, exec_context.group)
+$1.SupplementaryGroups,                  config_parse_user_group_strv_compat,         0,                                  offsetof($1, exec_context.supplementary_groups)
+$1.Nice,                                 config_parse_exec_nice,                      0,                                  offsetof($1, exec_context)
+$1.OOMScoreAdjust,                       config_parse_exec_oom_score_adjust,          0,                                  offsetof($1, exec_context)
+$1.CoredumpFilter,                       config_parse_exec_coredump_filter,           0,                                  offsetof($1, exec_context)
+$1.IOSchedulingClass,                    config_parse_exec_io_class,                  0,                                  offsetof($1, exec_context)
+$1.IOSchedulingPriority,                 config_parse_exec_io_priority,               0,                                  offsetof($1, exec_context)
+$1.CPUSchedulingPolicy,                  config_parse_exec_cpu_sched_policy,          0,                                  offsetof($1, exec_context)
+$1.CPUSchedulingPriority,                config_parse_exec_cpu_sched_prio,            0,                                  offsetof($1, exec_context)
+$1.CPUSchedulingResetOnFork,             config_parse_bool,                           0,                                  offsetof($1, exec_context.cpu_sched_reset_on_fork)
+$1.CPUAffinity,                          config_parse_exec_cpu_affinity,              0,                                  offsetof($1, exec_context)
+$1.NUMAPolicy,                           config_parse_numa_policy,                    0,                                  offsetof($1, exec_context.numa_policy.type)
+$1.NUMAMask,                             config_parse_numa_mask,                      0,                                  offsetof($1, exec_context.numa_policy)
+$1.UMask,                                config_parse_mode,                           0,                                  offsetof($1, exec_context.umask)
+$1.Environment,                          config_parse_environ,                        0,                                  offsetof($1, exec_context.environment)
+$1.EnvironmentFile,                      config_parse_unit_env_file,                  0,                                  offsetof($1, exec_context.environment_files)
+$1.PassEnvironment,                      config_parse_pass_environ,                   0,                                  offsetof($1, exec_context.pass_environment)
+$1.UnsetEnvironment,                     config_parse_unset_environ,                  0,                                  offsetof($1, exec_context.unset_environment)
+$1.DynamicUser,                          config_parse_bool,                           true,                               offsetof($1, exec_context.dynamic_user)
+$1.RemoveIPC,                            config_parse_bool,                           0,                                  offsetof($1, exec_context.remove_ipc)
+$1.StandardInput,                        config_parse_exec_input,                     0,                                  offsetof($1, exec_context)
+$1.StandardOutput,                       config_parse_exec_output,                    0,                                  offsetof($1, exec_context)
+$1.StandardError,                        config_parse_exec_output,                    0,                                  offsetof($1, exec_context)
+$1.StandardInputText,                    config_parse_exec_input_text,                0,                                  offsetof($1, exec_context)
+$1.StandardInputData,                    config_parse_exec_input_data,                0,                                  offsetof($1, exec_context)
+$1.TTYPath,                              config_parse_unit_path_printf,               0,                                  offsetof($1, exec_context.tty_path)
+$1.TTYReset,                             config_parse_bool,                           0,                                  offsetof($1, exec_context.tty_reset)
+$1.TTYVHangup,                           config_parse_bool,                           0,                                  offsetof($1, exec_context.tty_vhangup)
+$1.TTYVTDisallocate,                     config_parse_bool,                           0,                                  offsetof($1, exec_context.tty_vt_disallocate)
+$1.SyslogIdentifier,                     config_parse_unit_string_printf,             0,                                  offsetof($1, exec_context.syslog_identifier)
+$1.SyslogFacility,                       config_parse_log_facility,                   0,                                  offsetof($1, exec_context.syslog_priority)
+$1.SyslogLevel,                          config_parse_log_level,                      0,                                  offsetof($1, exec_context.syslog_priority)
+$1.SyslogLevelPrefix,                    config_parse_bool,                           0,                                  offsetof($1, exec_context.syslog_level_prefix)
+$1.LogLevelMax,                          config_parse_log_level,                      0,                                  offsetof($1, exec_context.log_level_max)
+$1.LogRateLimitIntervalSec,              config_parse_sec,                            0,                                  offsetof($1, exec_context.log_ratelimit_interval_usec)
+$1.LogRateLimitBurst,                    config_parse_unsigned,                       0,                                  offsetof($1, exec_context.log_ratelimit_burst)
+$1.LogExtraFields,                       config_parse_log_extra_fields,               0,                                  offsetof($1, exec_context)
+$1.Capabilities,                         config_parse_warn_compat,                    DISABLED_LEGACY,                    offsetof($1, exec_context)
+$1.SecureBits,                           config_parse_exec_secure_bits,               0,                                  offsetof($1, exec_context.secure_bits)
+$1.CapabilityBoundingSet,                config_parse_capability_set,                 0,                                  offsetof($1, exec_context.capability_bounding_set)
+$1.AmbientCapabilities,                  config_parse_capability_set,                 0,                                  offsetof($1, exec_context.capability_ambient_set)
+$1.TimerSlackNSec,                       config_parse_nsec,                           0,                                  offsetof($1, exec_context.timer_slack_nsec)
+$1.NoNewPrivileges,                      config_parse_bool,                           0,                                  offsetof($1, exec_context.no_new_privileges)
+$1.KeyringMode,                          config_parse_exec_keyring_mode,              0,                                  offsetof($1, exec_context.keyring_mode)
+$1.ProtectProc,                          config_parse_protect_proc,                   0,                                  offsetof($1, exec_context.protect_proc)
+$1.ProcSubset,                           config_parse_proc_subset,                    0,                                  offsetof($1, exec_context.proc_subset)
 m4_ifdef(`HAVE_SECCOMP',
-`$1.SystemCallFilter,            config_parse_syscall_filter,        0,                             offsetof($1, exec_context)
-$1.SystemCallArchitectures,      config_parse_syscall_archs,         0,                             offsetof($1, exec_context.syscall_archs)
-$1.SystemCallErrorNumber,        config_parse_syscall_errno,         0,                             offsetof($1, exec_context)
-$1.SystemCallLog,                config_parse_syscall_log,           0,                             offsetof($1, exec_context)
-$1.MemoryDenyWriteExecute,       config_parse_bool,                  0,                             offsetof($1, exec_context.memory_deny_write_execute)
-$1.RestrictNamespaces,           config_parse_restrict_namespaces,   0,                             offsetof($1, exec_context)
-$1.RestrictRealtime,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_realtime)
-$1.RestrictSUIDSGID,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_suid_sgid)
-$1.RestrictAddressFamilies,      config_parse_address_families,      0,                             offsetof($1, exec_context)
-$1.LockPersonality,              config_parse_bool,                  0,                             offsetof($1, exec_context.lock_personality)',
-`$1.SystemCallFilter,            config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.SystemCallArchitectures,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.SystemCallErrorNumber,        config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.SystemCallLog,                config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.MemoryDenyWriteExecute,       config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.RestrictNamespaces,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.RestrictRealtime,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.RestrictSUIDSGID,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.RestrictAddressFamilies,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-$1.LockPersonality,              config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
-$1.LimitCPU,                     config_parse_rlimit,                RLIMIT_CPU,                    offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE,                   config_parse_rlimit,                RLIMIT_FSIZE,                  offsetof($1, exec_context.rlimit)
-$1.LimitDATA,                    config_parse_rlimit,                RLIMIT_DATA,                   offsetof($1, exec_context.rlimit)
-$1.LimitSTACK,                   config_parse_rlimit,                RLIMIT_STACK,                  offsetof($1, exec_context.rlimit)
-$1.LimitCORE,                    config_parse_rlimit,                RLIMIT_CORE,                   offsetof($1, exec_context.rlimit)
-$1.LimitRSS,                     config_parse_rlimit,                RLIMIT_RSS,                    offsetof($1, exec_context.rlimit)
-$1.LimitNOFILE,                  config_parse_rlimit,                RLIMIT_NOFILE,                 offsetof($1, exec_context.rlimit)
-$1.LimitAS,                      config_parse_rlimit,                RLIMIT_AS,                     offsetof($1, exec_context.rlimit)
-$1.LimitNPROC,                   config_parse_rlimit,                RLIMIT_NPROC,                  offsetof($1, exec_context.rlimit)
-$1.LimitMEMLOCK,                 config_parse_rlimit,                RLIMIT_MEMLOCK,                offsetof($1, exec_context.rlimit)
-$1.LimitLOCKS,                   config_parse_rlimit,                RLIMIT_LOCKS,                  offsetof($1, exec_context.rlimit)
-$1.LimitSIGPENDING,              config_parse_rlimit,                RLIMIT_SIGPENDING,             offsetof($1, exec_context.rlimit)
-$1.LimitMSGQUEUE,                config_parse_rlimit,                RLIMIT_MSGQUEUE,               offsetof($1, exec_context.rlimit)
-$1.LimitNICE,                    config_parse_rlimit,                RLIMIT_NICE,                   offsetof($1, exec_context.rlimit)
-$1.LimitRTPRIO,                  config_parse_rlimit,                RLIMIT_RTPRIO,                 offsetof($1, exec_context.rlimit)
-$1.LimitRTTIME,                  config_parse_rlimit,                RLIMIT_RTTIME,                 offsetof($1, exec_context.rlimit)
-$1.ReadWriteDirectories,         config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_write_paths)
-$1.ReadOnlyDirectories,          config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_only_paths)
-$1.InaccessibleDirectories,      config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.inaccessible_paths)
-$1.ReadWritePaths,               config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_write_paths)
-$1.ReadOnlyPaths,                config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_only_paths)
-$1.InaccessiblePaths,            config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.inaccessible_paths)
-$1.BindPaths,                    config_parse_bind_paths,            0,                             offsetof($1, exec_context)
-$1.BindReadOnlyPaths,            config_parse_bind_paths,            0,                             offsetof($1, exec_context)
-$1.TemporaryFileSystem,          config_parse_temporary_filesystems, 0,                             offsetof($1, exec_context)
-$1.PrivateTmp,                   config_parse_bool,                  0,                             offsetof($1, exec_context.private_tmp)
-$1.PrivateDevices,               config_parse_bool,                  0,                             offsetof($1, exec_context.private_devices)
-$1.ProtectKernelTunables,        config_parse_bool,                  0,                             offsetof($1, exec_context.protect_kernel_tunables)
-$1.ProtectKernelModules,         config_parse_bool,                  0,                             offsetof($1, exec_context.protect_kernel_modules)
-$1.ProtectKernelLogs,            config_parse_bool,                  0,                             offsetof($1, exec_context.protect_kernel_logs)
-$1.ProtectClock,                 config_parse_bool,                  0,                             offsetof($1, exec_context.protect_clock)
-$1.ProtectControlGroups,         config_parse_bool,                  0,                             offsetof($1, exec_context.protect_control_groups)
-$1.NetworkNamespacePath,         config_parse_unit_path_printf,      0,                             offsetof($1, exec_context.network_namespace_path)
-$1.LogNamespace,                 config_parse_log_namespace,         0,                             offsetof($1, exec_context)
-$1.PrivateNetwork,               config_parse_bool,                  0,                             offsetof($1, exec_context.private_network)
-$1.PrivateUsers,                 config_parse_bool,                  0,                             offsetof($1, exec_context.private_users)
-$1.PrivateMounts,                config_parse_bool,                  0,                             offsetof($1, exec_context.private_mounts)
-$1.ProtectSystem,                config_parse_protect_system,        0,                             offsetof($1, exec_context.protect_system)
-$1.ProtectHome,                  config_parse_protect_home,          0,                             offsetof($1, exec_context.protect_home)
-$1.MountFlags,                   config_parse_exec_mount_flags,      0,                             offsetof($1, exec_context.mount_flags)
-$1.MountAPIVFS,                  config_parse_bool,                  0,                             offsetof($1, exec_context.mount_apivfs)
-$1.Personality,                  config_parse_personality,           0,                             offsetof($1, exec_context.personality)
-$1.RuntimeDirectoryPreserve,     config_parse_runtime_preserve_mode, 0,                             offsetof($1, exec_context.runtime_directory_preserve_mode)
-$1.RuntimeDirectoryMode,         config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
-$1.RuntimeDirectory,             config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].paths)
-$1.StateDirectoryMode,           config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
-$1.StateDirectory,               config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].paths)
-$1.CacheDirectoryMode,           config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
-$1.CacheDirectory,               config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].paths)
-$1.LogsDirectoryMode,            config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
-$1.LogsDirectory,                config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths)
-$1.ConfigurationDirectoryMode,   config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
-$1.ConfigurationDirectory,       config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
-$1.SetCredential,                config_parse_set_credential,        0,                             offsetof($1, exec_context)
-$1.LoadCredential,               config_parse_load_credential,       0,                             offsetof($1, exec_context)
-$1.TimeoutCleanSec,              config_parse_sec,                   0,                             offsetof($1, exec_context.timeout_clean_usec)
-$1.ProtectHostname,              config_parse_bool,                  0,                             offsetof($1, exec_context.protect_hostname)
+`$1.SystemCallFilter,                    config_parse_syscall_filter,                 0,                                  offsetof($1, exec_context)
+$1.SystemCallArchitectures,              config_parse_syscall_archs,                  0,                                  offsetof($1, exec_context.syscall_archs)
+$1.SystemCallErrorNumber,                config_parse_syscall_errno,                  0,                                  offsetof($1, exec_context)
+$1.SystemCallLog,                        config_parse_syscall_log,                    0,                                  offsetof($1, exec_context)
+$1.MemoryDenyWriteExecute,               config_parse_bool,                           0,                                  offsetof($1, exec_context.memory_deny_write_execute)
+$1.RestrictNamespaces,                   config_parse_restrict_namespaces,            0,                                  offsetof($1, exec_context)
+$1.RestrictRealtime,                     config_parse_bool,                           0,                                  offsetof($1, exec_context.restrict_realtime)
+$1.RestrictSUIDSGID,                     config_parse_bool,                           0,                                  offsetof($1, exec_context.restrict_suid_sgid)
+$1.RestrictAddressFamilies,              config_parse_address_families,               0,                                  offsetof($1, exec_context)
+$1.LockPersonality,                      config_parse_bool,                           0,                                  offsetof($1, exec_context.lock_personality)',
+`$1.SystemCallFilter,                    config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.SystemCallArchitectures,              config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.SystemCallErrorNumber,                config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.SystemCallLog,                        config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.MemoryDenyWriteExecute,               config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.RestrictNamespaces,                   config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.RestrictRealtime,                     config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.RestrictSUIDSGID,                     config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.RestrictAddressFamilies,              config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+$1.LockPersonality,                      config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
+$1.LimitCPU,                             config_parse_rlimit,                         RLIMIT_CPU,                         offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE,                           config_parse_rlimit,                         RLIMIT_FSIZE,                       offsetof($1, exec_context.rlimit)
+$1.LimitDATA,                            config_parse_rlimit,                         RLIMIT_DATA,                        offsetof($1, exec_context.rlimit)
+$1.LimitSTACK,                           config_parse_rlimit,                         RLIMIT_STACK,                       offsetof($1, exec_context.rlimit)
+$1.LimitCORE,                            config_parse_rlimit,                         RLIMIT_CORE,                        offsetof($1, exec_context.rlimit)
+$1.LimitRSS,                             config_parse_rlimit,                         RLIMIT_RSS,                         offsetof($1, exec_context.rlimit)
+$1.LimitNOFILE,                          config_parse_rlimit,                         RLIMIT_NOFILE,                      offsetof($1, exec_context.rlimit)
+$1.LimitAS,                              config_parse_rlimit,                         RLIMIT_AS,                          offsetof($1, exec_context.rlimit)
+$1.LimitNPROC,                           config_parse_rlimit,                         RLIMIT_NPROC,                       offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK,                         config_parse_rlimit,                         RLIMIT_MEMLOCK,                     offsetof($1, exec_context.rlimit)
+$1.LimitLOCKS,                           config_parse_rlimit,                         RLIMIT_LOCKS,                       offsetof($1, exec_context.rlimit)
+$1.LimitSIGPENDING,                      config_parse_rlimit,                         RLIMIT_SIGPENDING,                  offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE,                        config_parse_rlimit,                         RLIMIT_MSGQUEUE,                    offsetof($1, exec_context.rlimit)
+$1.LimitNICE,                            config_parse_rlimit,                         RLIMIT_NICE,                        offsetof($1, exec_context.rlimit)
+$1.LimitRTPRIO,                          config_parse_rlimit,                         RLIMIT_RTPRIO,                      offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME,                          config_parse_rlimit,                         RLIMIT_RTTIME,                      offsetof($1, exec_context.rlimit)
+$1.ReadWriteDirectories,                 config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.read_write_paths)
+$1.ReadOnlyDirectories,                  config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.read_only_paths)
+$1.InaccessibleDirectories,              config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.inaccessible_paths)
+$1.ReadWritePaths,                       config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.read_write_paths)
+$1.ReadOnlyPaths,                        config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.read_only_paths)
+$1.InaccessiblePaths,                    config_parse_namespace_path_strv,            0,                                  offsetof($1, exec_context.inaccessible_paths)
+$1.BindPaths,                            config_parse_bind_paths,                     0,                                  offsetof($1, exec_context)
+$1.BindReadOnlyPaths,                    config_parse_bind_paths,                     0,                                  offsetof($1, exec_context)
+$1.TemporaryFileSystem,                  config_parse_temporary_filesystems,          0,                                  offsetof($1, exec_context)
+$1.PrivateTmp,                           config_parse_bool,                           0,                                  offsetof($1, exec_context.private_tmp)
+$1.PrivateDevices,                       config_parse_bool,                           0,                                  offsetof($1, exec_context.private_devices)
+$1.ProtectKernelTunables,                config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_kernel_tunables)
+$1.ProtectKernelModules,                 config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_kernel_modules)
+$1.ProtectKernelLogs,                    config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_kernel_logs)
+$1.ProtectClock,                         config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_clock)
+$1.ProtectControlGroups,                 config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_control_groups)
+$1.NetworkNamespacePath,                 config_parse_unit_path_printf,               0,                                  offsetof($1, exec_context.network_namespace_path)
+$1.LogNamespace,                         config_parse_log_namespace,                  0,                                  offsetof($1, exec_context)
+$1.PrivateNetwork,                       config_parse_bool,                           0,                                  offsetof($1, exec_context.private_network)
+$1.PrivateUsers,                         config_parse_bool,                           0,                                  offsetof($1, exec_context.private_users)
+$1.PrivateMounts,                        config_parse_bool,                           0,                                  offsetof($1, exec_context.private_mounts)
+$1.ProtectSystem,                        config_parse_protect_system,                 0,                                  offsetof($1, exec_context.protect_system)
+$1.ProtectHome,                          config_parse_protect_home,                   0,                                  offsetof($1, exec_context.protect_home)
+$1.MountFlags,                           config_parse_exec_mount_flags,               0,                                  offsetof($1, exec_context.mount_flags)
+$1.MountAPIVFS,                          config_parse_bool,                           0,                                  offsetof($1, exec_context.mount_apivfs)
+$1.Personality,                          config_parse_personality,                    0,                                  offsetof($1, exec_context.personality)
+$1.RuntimeDirectoryPreserve,             config_parse_runtime_preserve_mode,          0,                                  offsetof($1, exec_context.runtime_directory_preserve_mode)
+$1.RuntimeDirectoryMode,                 config_parse_mode,                           0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
+$1.RuntimeDirectory,                     config_parse_exec_directories,               0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].paths)
+$1.StateDirectoryMode,                   config_parse_mode,                           0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
+$1.StateDirectory,                       config_parse_exec_directories,               0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].paths)
+$1.CacheDirectoryMode,                   config_parse_mode,                           0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
+$1.CacheDirectory,                       config_parse_exec_directories,               0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].paths)
+$1.LogsDirectoryMode,                    config_parse_mode,                           0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
+$1.LogsDirectory,                        config_parse_exec_directories,               0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths)
+$1.ConfigurationDirectoryMode,           config_parse_mode,                           0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
+$1.ConfigurationDirectory,               config_parse_exec_directories,               0,                                  offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
+$1.SetCredential,                        config_parse_set_credential,                 0,                                  offsetof($1, exec_context)
+$1.LoadCredential,                       config_parse_load_credential,                0,                                  offsetof($1, exec_context)
+$1.TimeoutCleanSec,                      config_parse_sec,                            0,                                  offsetof($1, exec_context.timeout_clean_usec)
+$1.ProtectHostname,                      config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_hostname)
 m4_ifdef(`HAVE_PAM',
-`$1.PAMName,                     config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.pam_name)',
-`$1.PAMName,                     config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
-$1.IgnoreSIGPIPE,                config_parse_bool,                  0,                             offsetof($1, exec_context.ignore_sigpipe)
-$1.UtmpIdentifier,               config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.utmp_id)
-$1.UtmpMode,                     config_parse_exec_utmp_mode,        0,                             offsetof($1, exec_context.utmp_mode)
+`$1.PAMName,                             config_parse_unit_string_printf,             0,                                  offsetof($1, exec_context.pam_name)',
+`$1.PAMName,                             config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
+$1.IgnoreSIGPIPE,                        config_parse_bool,                           0,                                  offsetof($1, exec_context.ignore_sigpipe)
+$1.UtmpIdentifier,                       config_parse_unit_string_printf,             0,                                  offsetof($1, exec_context.utmp_id)
+$1.UtmpMode,                             config_parse_exec_utmp_mode,                 0,                                  offsetof($1, exec_context.utmp_mode)
 m4_ifdef(`HAVE_SELINUX',
-`$1.SELinuxContext,              config_parse_exec_selinux_context,  0,                             offsetof($1, exec_context)',
-`$1.SELinuxContext,              config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
+`$1.SELinuxContext,                      config_parse_exec_selinux_context,           0,                                  offsetof($1, exec_context)',
+`$1.SELinuxContext,                      config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
 m4_ifdef(`HAVE_APPARMOR',
-`$1.AppArmorProfile,             config_parse_exec_apparmor_profile, 0,                             offsetof($1, exec_context)',
-`$1.AppArmorProfile,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
+`$1.AppArmorProfile,                     config_parse_exec_apparmor_profile,          0,                                  offsetof($1, exec_context)',
+`$1.AppArmorProfile,                     config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
 m4_ifdef(`ENABLE_SMACK',
-`$1.SmackProcessLabel,           config_parse_exec_smack_process_label, 0,                          offsetof($1, exec_context)',
-`$1.SmackProcessLabel,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')'
+`$1.SmackProcessLabel,                   config_parse_exec_smack_process_label,       0,                                  offsetof($1, exec_context)',
+`$1.SmackProcessLabel,                   config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')'
 )m4_dnl
 m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
-`$1.SendSIGKILL,                 config_parse_bool,                  0,                             offsetof($1, kill_context.send_sigkill)
-$1.SendSIGHUP,                   config_parse_bool,                  0,                             offsetof($1, kill_context.send_sighup)
-$1.KillMode,                     config_parse_kill_mode,             0,                             offsetof($1, kill_context.kill_mode)
-$1.KillSignal,                   config_parse_signal,                0,                             offsetof($1, kill_context.kill_signal)
-$1.RestartKillSignal,            config_parse_signal,                0,                             offsetof($1, kill_context.restart_kill_signal)
-$1.FinalKillSignal,              config_parse_signal,                0,                             offsetof($1, kill_context.final_kill_signal)
-$1.WatchdogSignal,               config_parse_signal,                0,                             offsetof($1, kill_context.watchdog_signal)'
+`$1.SendSIGKILL,                         config_parse_bool,                           0,                                  offsetof($1, kill_context.send_sigkill)
+$1.SendSIGHUP,                           config_parse_bool,                           0,                                  offsetof($1, kill_context.send_sighup)
+$1.KillMode,                             config_parse_kill_mode,                      0,                                  offsetof($1, kill_context.kill_mode)
+$1.KillSignal,                           config_parse_signal,                         0,                                  offsetof($1, kill_context.kill_signal)
+$1.RestartKillSignal,                    config_parse_signal,                         0,                                  offsetof($1, kill_context.restart_kill_signal)
+$1.FinalKillSignal,                      config_parse_signal,                         0,                                  offsetof($1, kill_context.final_kill_signal)
+$1.WatchdogSignal,                       config_parse_signal,                         0,                                  offsetof($1, kill_context.watchdog_signal)'
 )m4_dnl
 m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
-`$1.Slice,                       config_parse_unit_slice,            0,                             0
-$1.AllowedCPUs,                  config_parse_allowed_cpus,          0,                             offsetof($1, cgroup_context)
-$1.AllowedMemoryNodes,           config_parse_allowed_mems,          0,                             offsetof($1, cgroup_context)
-$1.CPUAccounting,                config_parse_bool,                  0,                             offsetof($1, cgroup_context.cpu_accounting)
-$1.CPUWeight,                    config_parse_cg_weight,             0,                             offsetof($1, cgroup_context.cpu_weight)
-$1.StartupCPUWeight,             config_parse_cg_weight,             0,                             offsetof($1, cgroup_context.startup_cpu_weight)
-$1.CPUShares,                    config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context.cpu_shares)
-$1.StartupCPUShares,             config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context.startup_cpu_shares)
-$1.CPUQuota,                     config_parse_cpu_quota,             0,                             offsetof($1, cgroup_context)
-$1.CPUQuotaPeriodSec,            config_parse_sec_def_infinity,      0,                             offsetof($1, cgroup_context.cpu_quota_period_usec)
-$1.MemoryAccounting,             config_parse_bool,                  0,                             offsetof($1, cgroup_context.memory_accounting)
-$1.MemoryMin,                    config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.DefaultMemoryMin,             config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.DefaultMemoryLow,             config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.MemoryLow,                    config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.MemoryHigh,                   config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.MemoryMax,                    config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.MemorySwapMax,                config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.MemoryLimit,                  config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
-$1.DeviceAllow,                  config_parse_device_allow,          0,                             offsetof($1, cgroup_context)
-$1.DevicePolicy,                 config_parse_device_policy,         0,                             offsetof($1, cgroup_context.device_policy)
-$1.IOAccounting,                 config_parse_bool,                  0,                             offsetof($1, cgroup_context.io_accounting)
-$1.IOWeight,                     config_parse_cg_weight,             0,                             offsetof($1, cgroup_context.io_weight)
-$1.StartupIOWeight,              config_parse_cg_weight,             0,                             offsetof($1, cgroup_context.startup_io_weight)
-$1.IODeviceWeight,               config_parse_io_device_weight,      0,                             offsetof($1, cgroup_context)
-$1.IOReadBandwidthMax,           config_parse_io_limit,              0,                             offsetof($1, cgroup_context)
-$1.IOWriteBandwidthMax,          config_parse_io_limit,              0,                             offsetof($1, cgroup_context)
-$1.IOReadIOPSMax,                config_parse_io_limit,              0,                             offsetof($1, cgroup_context)
-$1.IOWriteIOPSMax,               config_parse_io_limit,              0,                             offsetof($1, cgroup_context)
-$1.IODeviceLatencyTargetSec,     config_parse_io_device_latency,     0,                             offsetof($1, cgroup_context)
-$1.BlockIOAccounting,            config_parse_bool,                  0,                             offsetof($1, cgroup_context.blockio_accounting)
-$1.BlockIOWeight,                config_parse_blockio_weight,        0,                             offsetof($1, cgroup_context.blockio_weight)
-$1.StartupBlockIOWeight,         config_parse_blockio_weight,        0,                             offsetof($1, cgroup_context.startup_blockio_weight)
-$1.BlockIODeviceWeight,          config_parse_blockio_device_weight, 0,                             offsetof($1, cgroup_context)
-$1.BlockIOReadBandwidth,         config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
-$1.BlockIOWriteBandwidth,        config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
-$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)
-$1.IPIngressFilterPath,          config_parse_ip_filter_bpf_progs,   0,                             offsetof($1, cgroup_context.ip_filters_ingress)
-$1.IPEgressFilterPath,           config_parse_ip_filter_bpf_progs,   0,                             offsetof($1, cgroup_context.ip_filters_egress)
-$1.NetClass,                     config_parse_warn_compat,           DISABLED_LEGACY,               0'
+`$1.Slice,                               config_parse_unit_slice,                     0,                                  0
+$1.AllowedCPUs,                          config_parse_allowed_cpus,                   0,                                  offsetof($1, cgroup_context)
+$1.AllowedMemoryNodes,                   config_parse_allowed_mems,                   0,                                  offsetof($1, cgroup_context)
+$1.CPUAccounting,                        config_parse_bool,                           0,                                  offsetof($1, cgroup_context.cpu_accounting)
+$1.CPUWeight,                            config_parse_cg_weight,                      0,                                  offsetof($1, cgroup_context.cpu_weight)
+$1.StartupCPUWeight,                     config_parse_cg_weight,                      0,                                  offsetof($1, cgroup_context.startup_cpu_weight)
+$1.CPUShares,                            config_parse_cpu_shares,                     0,                                  offsetof($1, cgroup_context.cpu_shares)
+$1.StartupCPUShares,                     config_parse_cpu_shares,                     0,                                  offsetof($1, cgroup_context.startup_cpu_shares)
+$1.CPUQuota,                             config_parse_cpu_quota,                      0,                                  offsetof($1, cgroup_context)
+$1.CPUQuotaPeriodSec,                    config_parse_sec_def_infinity,               0,                                  offsetof($1, cgroup_context.cpu_quota_period_usec)
+$1.MemoryAccounting,                     config_parse_bool,                           0,                                  offsetof($1, cgroup_context.memory_accounting)
+$1.MemoryMin,                            config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.DefaultMemoryMin,                     config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.DefaultMemoryLow,                     config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.MemoryLow,                            config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.MemoryHigh,                           config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.MemoryMax,                            config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.MemorySwapMax,                        config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.MemoryLimit,                          config_parse_memory_limit,                   0,                                  offsetof($1, cgroup_context)
+$1.DeviceAllow,                          config_parse_device_allow,                   0,                                  offsetof($1, cgroup_context)
+$1.DevicePolicy,                         config_parse_device_policy,                  0,                                  offsetof($1, cgroup_context.device_policy)
+$1.IOAccounting,                         config_parse_bool,                           0,                                  offsetof($1, cgroup_context.io_accounting)
+$1.IOWeight,                             config_parse_cg_weight,                      0,                                  offsetof($1, cgroup_context.io_weight)
+$1.StartupIOWeight,                      config_parse_cg_weight,                      0,                                  offsetof($1, cgroup_context.startup_io_weight)
+$1.IODeviceWeight,                       config_parse_io_device_weight,               0,                                  offsetof($1, cgroup_context)
+$1.IOReadBandwidthMax,                   config_parse_io_limit,                       0,                                  offsetof($1, cgroup_context)
+$1.IOWriteBandwidthMax,                  config_parse_io_limit,                       0,                                  offsetof($1, cgroup_context)
+$1.IOReadIOPSMax,                        config_parse_io_limit,                       0,                                  offsetof($1, cgroup_context)
+$1.IOWriteIOPSMax,                       config_parse_io_limit,                       0,                                  offsetof($1, cgroup_context)
+$1.IODeviceLatencyTargetSec,             config_parse_io_device_latency,              0,                                  offsetof($1, cgroup_context)
+$1.BlockIOAccounting,                    config_parse_bool,                           0,                                  offsetof($1, cgroup_context.blockio_accounting)
+$1.BlockIOWeight,                        config_parse_blockio_weight,                 0,                                  offsetof($1, cgroup_context.blockio_weight)
+$1.StartupBlockIOWeight,                 config_parse_blockio_weight,                 0,                                  offsetof($1, cgroup_context.startup_blockio_weight)
+$1.BlockIODeviceWeight,                  config_parse_blockio_device_weight,          0,                                  offsetof($1, cgroup_context)
+$1.BlockIOReadBandwidth,                 config_parse_blockio_bandwidth,              0,                                  offsetof($1, cgroup_context)
+$1.BlockIOWriteBandwidth,                config_parse_blockio_bandwidth,              0,                                  offsetof($1, cgroup_context)
+$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)
+$1.IPIngressFilterPath,                  config_parse_ip_filter_bpf_progs,            0,                                  offsetof($1, cgroup_context.ip_filters_ingress)
+$1.IPEgressFilterPath,                   config_parse_ip_filter_bpf_progs,            0,                                  offsetof($1, cgroup_context.ip_filters_egress)
+$1.ManagedOOMSwap,                       config_parse_managed_oom_mode,               0,                                  offsetof($1, cgroup_context.moom_swap)
+$1.ManagedOOMMemoryPressure,             config_parse_managed_oom_mode,               0,                                  offsetof($1, cgroup_context.moom_mem_pressure)
+$1.ManagedOOMMemoryPressureLimitPercent, config_parse_managed_oom_mem_pressure_limit, 0,                                  offsetof($1, cgroup_context.moom_mem_pressure_limit)
+$1.NetClass,                             config_parse_warn_compat,                    DISABLED_LEGACY,                    0'
 )m4_dnl
-Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
-Unit.Documentation,              config_parse_documentation,         0,                             offsetof(Unit, documentation)
-Unit.SourcePath,                 config_parse_unit_path_printf,      0,                             offsetof(Unit, source_path)
-Unit.Requires,                   config_parse_unit_deps,             UNIT_REQUIRES,                 0
-Unit.Requisite,                  config_parse_unit_deps,             UNIT_REQUISITE,                0
-Unit.Wants,                      config_parse_unit_deps,             UNIT_WANTS,                    0
-Unit.BindsTo,                    config_parse_unit_deps,             UNIT_BINDS_TO,                 0
-Unit.BindTo,                     config_parse_unit_deps,             UNIT_BINDS_TO,                 0
-Unit.Conflicts,                  config_parse_unit_deps,             UNIT_CONFLICTS,                0
-Unit.Before,                     config_parse_unit_deps,             UNIT_BEFORE,                   0
-Unit.After,                      config_parse_unit_deps,             UNIT_AFTER,                    0
-Unit.OnFailure,                  config_parse_unit_deps,             UNIT_ON_FAILURE,               0
-Unit.PropagatesReloadTo,         config_parse_unit_deps,             UNIT_PROPAGATES_RELOAD_TO,     0
-Unit.PropagateReloadTo,          config_parse_unit_deps,             UNIT_PROPAGATES_RELOAD_TO,     0
-Unit.ReloadPropagatedFrom,       config_parse_unit_deps,             UNIT_RELOAD_PROPAGATED_FROM,   0
-Unit.PropagateReloadFrom,        config_parse_unit_deps,             UNIT_RELOAD_PROPAGATED_FROM,   0
-Unit.PartOf,                     config_parse_unit_deps,             UNIT_PART_OF,                  0
-Unit.JoinsNamespaceOf,           config_parse_unit_deps,             UNIT_JOINS_NAMESPACE_OF,       0
-Unit.RequiresOverridable,        config_parse_obsolete_unit_deps,    UNIT_REQUIRES,                 0
-Unit.RequisiteOverridable,       config_parse_obsolete_unit_deps,    UNIT_REQUISITE,                0
-Unit.RequiresMountsFor,          config_parse_unit_requires_mounts_for, 0,                          0
-Unit.StopWhenUnneeded,           config_parse_bool,                  0,                             offsetof(Unit, stop_when_unneeded)
-Unit.RefuseManualStart,          config_parse_bool,                  0,                             offsetof(Unit, refuse_manual_start)
-Unit.RefuseManualStop,           config_parse_bool,                  0,                             offsetof(Unit, refuse_manual_stop)
-Unit.AllowIsolate,               config_parse_bool,                  0,                             offsetof(Unit, allow_isolate)
-Unit.DefaultDependencies,        config_parse_bool,                  0,                             offsetof(Unit, default_dependencies)
-Unit.OnFailureJobMode,           config_parse_job_mode,              0,                             offsetof(Unit, on_failure_job_mode)
+Unit.Description,                        config_parse_unit_string_printf,             0,                                  offsetof(Unit, description)
+Unit.Documentation,                      config_parse_documentation,                  0,                                  offsetof(Unit, documentation)
+Unit.SourcePath,                         config_parse_unit_path_printf,               0,                                  offsetof(Unit, source_path)
+Unit.Requires,                           config_parse_unit_deps,                      UNIT_REQUIRES,                      0
+Unit.Requisite,                          config_parse_unit_deps,                      UNIT_REQUISITE,                     0
+Unit.Wants,                              config_parse_unit_deps,                      UNIT_WANTS,                         0
+Unit.BindsTo,                            config_parse_unit_deps,                      UNIT_BINDS_TO,                      0
+Unit.BindTo,                             config_parse_unit_deps,                      UNIT_BINDS_TO,                      0
+Unit.Conflicts,                          config_parse_unit_deps,                      UNIT_CONFLICTS,                     0
+Unit.Before,                             config_parse_unit_deps,                      UNIT_BEFORE,                        0
+Unit.After,                              config_parse_unit_deps,                      UNIT_AFTER,                         0
+Unit.OnFailure,                          config_parse_unit_deps,                      UNIT_ON_FAILURE,                    0
+Unit.PropagatesReloadTo,                 config_parse_unit_deps,                      UNIT_PROPAGATES_RELOAD_TO,          0
+Unit.PropagateReloadTo,                  config_parse_unit_deps,                      UNIT_PROPAGATES_RELOAD_TO,          0
+Unit.ReloadPropagatedFrom,               config_parse_unit_deps,                      UNIT_RELOAD_PROPAGATED_FROM,        0
+Unit.PropagateReloadFrom,                config_parse_unit_deps,                      UNIT_RELOAD_PROPAGATED_FROM,        0
+Unit.PartOf,                             config_parse_unit_deps,                      UNIT_PART_OF,                       0
+Unit.JoinsNamespaceOf,                   config_parse_unit_deps,                      UNIT_JOINS_NAMESPACE_OF,            0
+Unit.RequiresOverridable,                config_parse_obsolete_unit_deps,             UNIT_REQUIRES,                      0
+Unit.RequisiteOverridable,               config_parse_obsolete_unit_deps,             UNIT_REQUISITE,                     0
+Unit.RequiresMountsFor,                  config_parse_unit_requires_mounts_for,       0,                                  0
+Unit.StopWhenUnneeded,                   config_parse_bool,                           0,                                  offsetof(Unit, stop_when_unneeded)
+Unit.RefuseManualStart,                  config_parse_bool,                           0,                                  offsetof(Unit, refuse_manual_start)
+Unit.RefuseManualStop,                   config_parse_bool,                           0,                                  offsetof(Unit, refuse_manual_stop)
+Unit.AllowIsolate,                       config_parse_bool,                           0,                                  offsetof(Unit, allow_isolate)
+Unit.DefaultDependencies,                config_parse_bool,                           0,                                  offsetof(Unit, default_dependencies)
+Unit.OnFailureJobMode,                   config_parse_job_mode,                       0,                                  offsetof(Unit, on_failure_job_mode)
 m4_dnl The following is a legacy alias name for compatibility
-Unit.OnFailureIsolate,           config_parse_job_mode_isolate,      0,                             offsetof(Unit, on_failure_job_mode)
-Unit.IgnoreOnIsolate,            config_parse_bool,                  0,                             offsetof(Unit, ignore_on_isolate)
-Unit.IgnoreOnSnapshot,           config_parse_warn_compat,           DISABLED_LEGACY,               0
-Unit.JobTimeoutSec,              config_parse_job_timeout_sec,       0,                             0
-Unit.JobRunningTimeoutSec,       config_parse_job_running_timeout_sec, 0,                           0
-Unit.JobTimeoutAction,           config_parse_emergency_action,      0,                             offsetof(Unit, job_timeout_action)
-Unit.JobTimeoutRebootArgument,   config_parse_unit_string_printf,    0,                             offsetof(Unit, job_timeout_reboot_arg)
-Unit.StartLimitIntervalSec,      config_parse_sec,                   0,                             offsetof(Unit, start_ratelimit.interval)
+Unit.OnFailureIsolate,                   config_parse_job_mode_isolate,               0,                                  offsetof(Unit, on_failure_job_mode)
+Unit.IgnoreOnIsolate,                    config_parse_bool,                           0,                                  offsetof(Unit, ignore_on_isolate)
+Unit.IgnoreOnSnapshot,                   config_parse_warn_compat,                    DISABLED_LEGACY,                    0
+Unit.JobTimeoutSec,                      config_parse_job_timeout_sec,                0,                                  0
+Unit.JobRunningTimeoutSec,               config_parse_job_running_timeout_sec,        0,                                  0
+Unit.JobTimeoutAction,                   config_parse_emergency_action,               0,                                  offsetof(Unit, job_timeout_action)
+Unit.JobTimeoutRebootArgument,           config_parse_unit_string_printf,             0,                                  offsetof(Unit, job_timeout_reboot_arg)
+Unit.StartLimitIntervalSec,              config_parse_sec,                            0,                                  offsetof(Unit, start_ratelimit.interval)
 m4_dnl The following is a legacy alias name for compatibility
-Unit.StartLimitInterval,         config_parse_sec,                   0,                             offsetof(Unit, start_ratelimit.interval)
-Unit.StartLimitBurst,            config_parse_unsigned,              0,                             offsetof(Unit, start_ratelimit.burst)
-Unit.StartLimitAction,           config_parse_emergency_action,      0,                             offsetof(Unit, start_limit_action)
-Unit.FailureAction,              config_parse_emergency_action,      0,                             offsetof(Unit, failure_action)
-Unit.SuccessAction,              config_parse_emergency_action,      0,                             offsetof(Unit, success_action)
-Unit.FailureActionExitStatus,    config_parse_exit_status,           0,                             offsetof(Unit, failure_action_exit_status)
-Unit.SuccessActionExitStatus,    config_parse_exit_status,           0,                             offsetof(Unit, success_action_exit_status)
-Unit.RebootArgument,             config_parse_unit_string_printf,    0,                             offsetof(Unit, reboot_arg)
-Unit.ConditionPathExists,        config_parse_unit_condition_path,   CONDITION_PATH_EXISTS,         offsetof(Unit, conditions)
-Unit.ConditionPathExistsGlob,    config_parse_unit_condition_path,   CONDITION_PATH_EXISTS_GLOB,    offsetof(Unit, conditions)
-Unit.ConditionPathIsDirectory,   config_parse_unit_condition_path,   CONDITION_PATH_IS_DIRECTORY,   offsetof(Unit, conditions)
-Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path,   CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, conditions)
-Unit.ConditionPathIsMountPoint,  config_parse_unit_condition_path,   CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
-Unit.ConditionPathIsReadWrite,   config_parse_unit_condition_path,   CONDITION_PATH_IS_READ_WRITE,  offsetof(Unit, conditions)
-Unit.ConditionPathIsEncrypted,   config_parse_unit_condition_path,   CONDITION_PATH_IS_ENCRYPTED,   offsetof(Unit, conditions)
-Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path,   CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
-Unit.ConditionFileNotEmpty,      config_parse_unit_condition_path,   CONDITION_FILE_NOT_EMPTY,      offsetof(Unit, conditions)
-Unit.ConditionFileIsExecutable,  config_parse_unit_condition_path,   CONDITION_FILE_IS_EXECUTABLE,  offsetof(Unit, conditions)
-Unit.ConditionNeedsUpdate,       config_parse_unit_condition_path,   CONDITION_NEEDS_UPDATE,        offsetof(Unit, conditions)
-Unit.ConditionFirstBoot,         config_parse_unit_condition_string, CONDITION_FIRST_BOOT,          offsetof(Unit, conditions)
-Unit.ConditionArchitecture,      config_parse_unit_condition_string, CONDITION_ARCHITECTURE,        offsetof(Unit, conditions)
-Unit.ConditionVirtualization,    config_parse_unit_condition_string, CONDITION_VIRTUALIZATION,      offsetof(Unit, conditions)
-Unit.ConditionHost,              config_parse_unit_condition_string, CONDITION_HOST,                offsetof(Unit, conditions)
-Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)
-Unit.ConditionKernelVersion,     config_parse_unit_condition_string, CONDITION_KERNEL_VERSION,      offsetof(Unit, conditions)
-Unit.ConditionSecurity,          config_parse_unit_condition_string, CONDITION_SECURITY,            offsetof(Unit, conditions)
-Unit.ConditionCapability,        config_parse_unit_condition_string, CONDITION_CAPABILITY,          offsetof(Unit, conditions)
-Unit.ConditionACPower,           config_parse_unit_condition_string, CONDITION_AC_POWER,            offsetof(Unit, conditions)
-Unit.ConditionMemory,            config_parse_unit_condition_string, CONDITION_MEMORY,              offsetof(Unit, conditions)
-Unit.ConditionCPUs,              config_parse_unit_condition_string, CONDITION_CPUS,                offsetof(Unit, conditions)
-Unit.ConditionEnvironment,       config_parse_unit_condition_string, CONDITION_ENVIRONMENT,         offsetof(Unit, conditions)
-Unit.ConditionUser,              config_parse_unit_condition_string, CONDITION_USER,                offsetof(Unit, conditions)
-Unit.ConditionGroup,             config_parse_unit_condition_string, CONDITION_GROUP,               offsetof(Unit, conditions)
-Unit.ConditionControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, conditions)
-Unit.AssertPathExists,           config_parse_unit_condition_path,   CONDITION_PATH_EXISTS,         offsetof(Unit, asserts)
-Unit.AssertPathExistsGlob,       config_parse_unit_condition_path,   CONDITION_PATH_EXISTS_GLOB,    offsetof(Unit, asserts)
-Unit.AssertPathIsDirectory,      config_parse_unit_condition_path,   CONDITION_PATH_IS_DIRECTORY,   offsetof(Unit, asserts)
-Unit.AssertPathIsSymbolicLink,   config_parse_unit_condition_path,   CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, asserts)
-Unit.AssertPathIsMountPoint,     config_parse_unit_condition_path,   CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
-Unit.AssertPathIsReadWrite,      config_parse_unit_condition_path,   CONDITION_PATH_IS_READ_WRITE,  offsetof(Unit, asserts)
-Unit.AssertPathIsEncrypted,      config_parse_unit_condition_path,   CONDITION_PATH_IS_ENCRYPTED,   offsetof(Unit, asserts)
-Unit.AssertDirectoryNotEmpty,    config_parse_unit_condition_path,   CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
-Unit.AssertFileNotEmpty,         config_parse_unit_condition_path,   CONDITION_FILE_NOT_EMPTY,      offsetof(Unit, asserts)
-Unit.AssertFileIsExecutable,     config_parse_unit_condition_path,   CONDITION_FILE_IS_EXECUTABLE,  offsetof(Unit, asserts)
-Unit.AssertNeedsUpdate,          config_parse_unit_condition_path,   CONDITION_NEEDS_UPDATE,        offsetof(Unit, asserts)
-Unit.AssertFirstBoot,            config_parse_unit_condition_string, CONDITION_FIRST_BOOT,          offsetof(Unit, asserts)
-Unit.AssertArchitecture,         config_parse_unit_condition_string, CONDITION_ARCHITECTURE,        offsetof(Unit, asserts)
-Unit.AssertVirtualization,       config_parse_unit_condition_string, CONDITION_VIRTUALIZATION,      offsetof(Unit, asserts)
-Unit.AssertHost,                 config_parse_unit_condition_string, CONDITION_HOST,                offsetof(Unit, asserts)
-Unit.AssertKernelCommandLine,    config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts)
-Unit.AssertKernelVersion,        config_parse_unit_condition_string, CONDITION_KERNEL_VERSION,      offsetof(Unit, asserts)
-Unit.AssertSecurity,             config_parse_unit_condition_string, CONDITION_SECURITY,            offsetof(Unit, asserts)
-Unit.AssertCapability,           config_parse_unit_condition_string, CONDITION_CAPABILITY,          offsetof(Unit, asserts)
-Unit.AssertACPower,              config_parse_unit_condition_string, CONDITION_AC_POWER,            offsetof(Unit, asserts)
-Unit.AssertMemory,               config_parse_unit_condition_string, CONDITION_MEMORY,              offsetof(Unit, asserts)
-Unit.AssertCPUs,                 config_parse_unit_condition_string, CONDITION_CPUS,                offsetof(Unit, asserts)
-Unit.AssertEnvironment,          config_parse_unit_condition_string, CONDITION_ENVIRONMENT,         offsetof(Unit, asserts)
-Unit.AssertUser,                 config_parse_unit_condition_string, CONDITION_USER,                offsetof(Unit, asserts)
-Unit.AssertGroup,                config_parse_unit_condition_string, CONDITION_GROUP,               offsetof(Unit, asserts)
-Unit.AssertControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, asserts)
-Unit.CollectMode,                config_parse_collect_mode,          0,                             offsetof(Unit, collect_mode)
+Unit.StartLimitInterval,                 config_parse_sec,                            0,                                  offsetof(Unit, start_ratelimit.interval)
+Unit.StartLimitBurst,                    config_parse_unsigned,                       0,                                  offsetof(Unit, start_ratelimit.burst)
+Unit.StartLimitAction,                   config_parse_emergency_action,               0,                                  offsetof(Unit, start_limit_action)
+Unit.FailureAction,                      config_parse_emergency_action,               0,                                  offsetof(Unit, failure_action)
+Unit.SuccessAction,                      config_parse_emergency_action,               0,                                  offsetof(Unit, success_action)
+Unit.FailureActionExitStatus,            config_parse_exit_status,                    0,                                  offsetof(Unit, failure_action_exit_status)
+Unit.SuccessActionExitStatus,            config_parse_exit_status,                    0,                                  offsetof(Unit, success_action_exit_status)
+Unit.RebootArgument,                     config_parse_unit_string_printf,             0,                                  offsetof(Unit, reboot_arg)
+Unit.ConditionPathExists,                config_parse_unit_condition_path,            CONDITION_PATH_EXISTS,              offsetof(Unit, conditions)
+Unit.ConditionPathExistsGlob,            config_parse_unit_condition_path,            CONDITION_PATH_EXISTS_GLOB,         offsetof(Unit, conditions)
+Unit.ConditionPathIsDirectory,           config_parse_unit_condition_path,            CONDITION_PATH_IS_DIRECTORY,        offsetof(Unit, conditions)
+Unit.ConditionPathIsSymbolicLink,        config_parse_unit_condition_path,            CONDITION_PATH_IS_SYMBOLIC_LINK,    offsetof(Unit, conditions)
+Unit.ConditionPathIsMountPoint,          config_parse_unit_condition_path,            CONDITION_PATH_IS_MOUNT_POINT,      offsetof(Unit, conditions)
+Unit.ConditionPathIsReadWrite,           config_parse_unit_condition_path,            CONDITION_PATH_IS_READ_WRITE,       offsetof(Unit, conditions)
+Unit.ConditionPathIsEncrypted,           config_parse_unit_condition_path,            CONDITION_PATH_IS_ENCRYPTED,        offsetof(Unit, conditions)
+Unit.ConditionDirectoryNotEmpty,         config_parse_unit_condition_path,            CONDITION_DIRECTORY_NOT_EMPTY,      offsetof(Unit, conditions)
+Unit.ConditionFileNotEmpty,              config_parse_unit_condition_path,            CONDITION_FILE_NOT_EMPTY,           offsetof(Unit, conditions)
+Unit.ConditionFileIsExecutable,          config_parse_unit_condition_path,            CONDITION_FILE_IS_EXECUTABLE,       offsetof(Unit, conditions)
+Unit.ConditionNeedsUpdate,               config_parse_unit_condition_path,            CONDITION_NEEDS_UPDATE,             offsetof(Unit, conditions)
+Unit.ConditionFirstBoot,                 config_parse_unit_condition_string,          CONDITION_FIRST_BOOT,               offsetof(Unit, conditions)
+Unit.ConditionArchitecture,              config_parse_unit_condition_string,          CONDITION_ARCHITECTURE,             offsetof(Unit, conditions)
+Unit.ConditionVirtualization,            config_parse_unit_condition_string,          CONDITION_VIRTUALIZATION,           offsetof(Unit, conditions)
+Unit.ConditionHost,                      config_parse_unit_condition_string,          CONDITION_HOST,                     offsetof(Unit, conditions)
+Unit.ConditionKernelCommandLine,         config_parse_unit_condition_string,          CONDITION_KERNEL_COMMAND_LINE,      offsetof(Unit, conditions)
+Unit.ConditionKernelVersion,             config_parse_unit_condition_string,          CONDITION_KERNEL_VERSION,           offsetof(Unit, conditions)
+Unit.ConditionSecurity,                  config_parse_unit_condition_string,          CONDITION_SECURITY,                 offsetof(Unit, conditions)
+Unit.ConditionCapability,                config_parse_unit_condition_string,          CONDITION_CAPABILITY,               offsetof(Unit, conditions)
+Unit.ConditionACPower,                   config_parse_unit_condition_string,          CONDITION_AC_POWER,                 offsetof(Unit, conditions)
+Unit.ConditionMemory,                    config_parse_unit_condition_string,          CONDITION_MEMORY,                   offsetof(Unit, conditions)
+Unit.ConditionCPUs,                      config_parse_unit_condition_string,          CONDITION_CPUS,                     offsetof(Unit, conditions)
+Unit.ConditionEnvironment,               config_parse_unit_condition_string,          CONDITION_ENVIRONMENT,              offsetof(Unit, conditions)
+Unit.ConditionUser,                      config_parse_unit_condition_string,          CONDITION_USER,                     offsetof(Unit, conditions)
+Unit.ConditionGroup,                     config_parse_unit_condition_string,          CONDITION_GROUP,                    offsetof(Unit, conditions)
+Unit.ConditionControlGroupController,    config_parse_unit_condition_string,          CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, conditions)
+Unit.AssertPathExists,                   config_parse_unit_condition_path,            CONDITION_PATH_EXISTS,              offsetof(Unit, asserts)
+Unit.AssertPathExistsGlob,               config_parse_unit_condition_path,            CONDITION_PATH_EXISTS_GLOB,         offsetof(Unit, asserts)
+Unit.AssertPathIsDirectory,              config_parse_unit_condition_path,            CONDITION_PATH_IS_DIRECTORY,        offsetof(Unit, asserts)
+Unit.AssertPathIsSymbolicLink,           config_parse_unit_condition_path,            CONDITION_PATH_IS_SYMBOLIC_LINK,    offsetof(Unit, asserts)
+Unit.AssertPathIsMountPoint,             config_parse_unit_condition_path,            CONDITION_PATH_IS_MOUNT_POINT,      offsetof(Unit, asserts)
+Unit.AssertPathIsReadWrite,              config_parse_unit_condition_path,            CONDITION_PATH_IS_READ_WRITE,       offsetof(Unit, asserts)
+Unit.AssertPathIsEncrypted,              config_parse_unit_condition_path,            CONDITION_PATH_IS_ENCRYPTED,        offsetof(Unit, asserts)
+Unit.AssertDirectoryNotEmpty,            config_parse_unit_condition_path,            CONDITION_DIRECTORY_NOT_EMPTY,      offsetof(Unit, asserts)
+Unit.AssertFileNotEmpty,                 config_parse_unit_condition_path,            CONDITION_FILE_NOT_EMPTY,           offsetof(Unit, asserts)
+Unit.AssertFileIsExecutable,             config_parse_unit_condition_path,            CONDITION_FILE_IS_EXECUTABLE,       offsetof(Unit, asserts)
+Unit.AssertNeedsUpdate,                  config_parse_unit_condition_path,            CONDITION_NEEDS_UPDATE,             offsetof(Unit, asserts)
+Unit.AssertFirstBoot,                    config_parse_unit_condition_string,          CONDITION_FIRST_BOOT,               offsetof(Unit, asserts)
+Unit.AssertArchitecture,                 config_parse_unit_condition_string,          CONDITION_ARCHITECTURE,             offsetof(Unit, asserts)
+Unit.AssertVirtualization,               config_parse_unit_condition_string,          CONDITION_VIRTUALIZATION,           offsetof(Unit, asserts)
+Unit.AssertHost,                         config_parse_unit_condition_string,          CONDITION_HOST,                     offsetof(Unit, asserts)
+Unit.AssertKernelCommandLine,            config_parse_unit_condition_string,          CONDITION_KERNEL_COMMAND_LINE,      offsetof(Unit, asserts)
+Unit.AssertKernelVersion,                config_parse_unit_condition_string,          CONDITION_KERNEL_VERSION,           offsetof(Unit, asserts)
+Unit.AssertSecurity,                     config_parse_unit_condition_string,          CONDITION_SECURITY,                 offsetof(Unit, asserts)
+Unit.AssertCapability,                   config_parse_unit_condition_string,          CONDITION_CAPABILITY,               offsetof(Unit, asserts)
+Unit.AssertACPower,                      config_parse_unit_condition_string,          CONDITION_AC_POWER,                 offsetof(Unit, asserts)
+Unit.AssertMemory,                       config_parse_unit_condition_string,          CONDITION_MEMORY,                   offsetof(Unit, asserts)
+Unit.AssertCPUs,                         config_parse_unit_condition_string,          CONDITION_CPUS,                     offsetof(Unit, asserts)
+Unit.AssertEnvironment,                  config_parse_unit_condition_string,          CONDITION_ENVIRONMENT,              offsetof(Unit, asserts)
+Unit.AssertUser,                         config_parse_unit_condition_string,          CONDITION_USER,                     offsetof(Unit, asserts)
+Unit.AssertGroup,                        config_parse_unit_condition_string,          CONDITION_GROUP,                    offsetof(Unit, asserts)
+Unit.AssertControlGroupController,       config_parse_unit_condition_string,          CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, asserts)
+Unit.CollectMode,                        config_parse_collect_mode,                   0,                                  offsetof(Unit, collect_mode)
 m4_dnl
-Service.PIDFile,                 config_parse_pid_file,              0,                             offsetof(Service, pid_file)
-Service.ExecCondition,           config_parse_exec,                  SERVICE_EXEC_CONDITION,        offsetof(Service, exec_command)
-Service.ExecStartPre,            config_parse_exec,                  SERVICE_EXEC_START_PRE,        offsetof(Service, exec_command)
-Service.ExecStart,               config_parse_exec,                  SERVICE_EXEC_START,            offsetof(Service, exec_command)
-Service.ExecStartPost,           config_parse_exec,                  SERVICE_EXEC_START_POST,       offsetof(Service, exec_command)
-Service.ExecReload,              config_parse_exec,                  SERVICE_EXEC_RELOAD,           offsetof(Service, exec_command)
-Service.ExecStop,                config_parse_exec,                  SERVICE_EXEC_STOP,             offsetof(Service, exec_command)
-Service.ExecStopPost,            config_parse_exec,                  SERVICE_EXEC_STOP_POST,        offsetof(Service, exec_command)
-Service.RestartSec,              config_parse_sec,                   0,                             offsetof(Service, restart_usec)
-Service.TimeoutSec,              config_parse_service_timeout,       0,                             0
-Service.TimeoutStartSec,         config_parse_service_timeout,       0,                             0
-Service.TimeoutStopSec,          config_parse_sec_fix_0,             0,                             offsetof(Service, timeout_stop_usec)
-Service.TimeoutAbortSec,         config_parse_service_timeout_abort, 0,                             0
-Service.TimeoutStartFailureMode, config_parse_service_timeout_failure_mode,  0,                     offsetof(Service, timeout_start_failure_mode)
-Service.TimeoutStopFailureMode,  config_parse_service_timeout_failure_mode,  0,                     offsetof(Service, timeout_stop_failure_mode)
-Service.RuntimeMaxSec,           config_parse_sec,                   0,                             offsetof(Service, runtime_max_usec)
-Service.WatchdogSec,             config_parse_sec,                   0,                             offsetof(Service, watchdog_usec)
+Service.PIDFile,                         config_parse_pid_file,                       0,                                  offsetof(Service, pid_file)
+Service.ExecCondition,                   config_parse_exec,                           SERVICE_EXEC_CONDITION,             offsetof(Service, exec_command)
+Service.ExecStartPre,                    config_parse_exec,                           SERVICE_EXEC_START_PRE,             offsetof(Service, exec_command)
+Service.ExecStart,                       config_parse_exec,                           SERVICE_EXEC_START,                 offsetof(Service, exec_command)
+Service.ExecStartPost,                   config_parse_exec,                           SERVICE_EXEC_START_POST,            offsetof(Service, exec_command)
+Service.ExecReload,                      config_parse_exec,                           SERVICE_EXEC_RELOAD,                offsetof(Service, exec_command)
+Service.ExecStop,                        config_parse_exec,                           SERVICE_EXEC_STOP,                  offsetof(Service, exec_command)
+Service.ExecStopPost,                    config_parse_exec,                           SERVICE_EXEC_STOP_POST,             offsetof(Service, exec_command)
+Service.RestartSec,                      config_parse_sec,                            0,                                  offsetof(Service, restart_usec)
+Service.TimeoutSec,                      config_parse_service_timeout,                0,                                  0
+Service.TimeoutStartSec,                 config_parse_service_timeout,                0,                                  0
+Service.TimeoutStopSec,                  config_parse_sec_fix_0,                      0,                                  offsetof(Service, timeout_stop_usec)
+Service.TimeoutAbortSec,                 config_parse_service_timeout_abort,          0,                                  0
+Service.TimeoutStartFailureMode,         config_parse_service_timeout_failure_mode,   0,                                  offsetof(Service, timeout_start_failure_mode)
+Service.TimeoutStopFailureMode,          config_parse_service_timeout_failure_mode,   0,                                  offsetof(Service, timeout_stop_failure_mode)
+Service.RuntimeMaxSec,                   config_parse_sec,                            0,                                  offsetof(Service, runtime_max_usec)
+Service.WatchdogSec,                     config_parse_sec,                            0,                                  offsetof(Service, watchdog_usec)
 m4_dnl The following five only exist for compatibility, they moved into Unit, see above
-Service.StartLimitInterval,      config_parse_sec,                   0,                             offsetof(Unit, start_ratelimit.interval)
-Service.StartLimitBurst,         config_parse_unsigned,              0,                             offsetof(Unit, start_ratelimit.burst)
-Service.StartLimitAction,        config_parse_emergency_action,      0,                             offsetof(Unit, start_limit_action)
-Service.FailureAction,           config_parse_emergency_action,      0,                             offsetof(Unit, failure_action)
-Service.RebootArgument,          config_parse_unit_string_printf,    0,                             offsetof(Unit, reboot_arg)
-Service.Type,                    config_parse_service_type,          0,                             offsetof(Service, type)
-Service.Restart,                 config_parse_service_restart,       0,                             offsetof(Service, restart)
-Service.PermissionsStartOnly,    config_parse_bool,                  0,                             offsetof(Service, permissions_start_only)
-Service.RootDirectoryStartOnly,  config_parse_bool,                  0,                             offsetof(Service, root_directory_start_only)
-Service.RemainAfterExit,         config_parse_bool,                  0,                             offsetof(Service, remain_after_exit)
-Service.GuessMainPID,            config_parse_bool,                  0,                             offsetof(Service, guess_main_pid)
-Service.RestartPreventExitStatus, config_parse_set_status,           0,                             offsetof(Service, restart_prevent_status)
-Service.RestartForceExitStatus,  config_parse_set_status,            0,                             offsetof(Service, restart_force_status)
-Service.SuccessExitStatus,       config_parse_set_status,            0,                             offsetof(Service, success_status)
-Service.SysVStartPriority,       config_parse_warn_compat,           DISABLED_LEGACY,               0
-Service.NonBlocking,             config_parse_bool,                  0,                             offsetof(Service, exec_context.non_blocking)
-Service.BusName,                 config_parse_bus_name,              0,                             offsetof(Service, bus_name)
-Service.FileDescriptorStoreMax,  config_parse_unsigned,              0,                             offsetof(Service, n_fd_store_max)
-Service.NotifyAccess,            config_parse_notify_access,         0,                             offsetof(Service, notify_access)
-Service.Sockets,                 config_parse_service_sockets,       0,                             0
-Service.BusPolicy,               config_parse_warn_compat,           DISABLED_LEGACY,               0
-Service.USBFunctionDescriptors,  config_parse_unit_path_printf,      0,                             offsetof(Service, usb_function_descriptors)
-Service.USBFunctionStrings,      config_parse_unit_path_printf,      0,                             offsetof(Service, usb_function_strings)
-Service.OOMPolicy,               config_parse_oom_policy,            0,                             offsetof(Service, oom_policy)
+Service.StartLimitInterval,              config_parse_sec,                            0,                                  offsetof(Unit, start_ratelimit.interval)
+Service.StartLimitBurst,                 config_parse_unsigned,                       0,                                  offsetof(Unit, start_ratelimit.burst)
+Service.StartLimitAction,                config_parse_emergency_action,               0,                                  offsetof(Unit, start_limit_action)
+Service.FailureAction,                   config_parse_emergency_action,               0,                                  offsetof(Unit, failure_action)
+Service.RebootArgument,                  config_parse_unit_string_printf,             0,                                  offsetof(Unit, reboot_arg)
+Service.Type,                            config_parse_service_type,                   0,                                  offsetof(Service, type)
+Service.Restart,                         config_parse_service_restart,                0,                                  offsetof(Service, restart)
+Service.PermissionsStartOnly,            config_parse_bool,                           0,                                  offsetof(Service, permissions_start_only)
+Service.RootDirectoryStartOnly,          config_parse_bool,                           0,                                  offsetof(Service, root_directory_start_only)
+Service.RemainAfterExit,                 config_parse_bool,                           0,                                  offsetof(Service, remain_after_exit)
+Service.GuessMainPID,                    config_parse_bool,                           0,                                  offsetof(Service, guess_main_pid)
+Service.RestartPreventExitStatus,        config_parse_set_status,                     0,                                  offsetof(Service, restart_prevent_status)
+Service.RestartForceExitStatus,          config_parse_set_status,                     0,                                  offsetof(Service, restart_force_status)
+Service.SuccessExitStatus,               config_parse_set_status,                     0,                                  offsetof(Service, success_status)
+Service.SysVStartPriority,               config_parse_warn_compat,                    DISABLED_LEGACY,                    0
+Service.NonBlocking,                     config_parse_bool,                           0,                                  offsetof(Service, exec_context.non_blocking)
+Service.BusName,                         config_parse_bus_name,                       0,                                  offsetof(Service, bus_name)
+Service.FileDescriptorStoreMax,          config_parse_unsigned,                       0,                                  offsetof(Service, n_fd_store_max)
+Service.NotifyAccess,                    config_parse_notify_access,                  0,                                  offsetof(Service, notify_access)
+Service.Sockets,                         config_parse_service_sockets,                0,                                  0
+Service.BusPolicy,                       config_parse_warn_compat,                    DISABLED_LEGACY,                    0
+Service.USBFunctionDescriptors,          config_parse_unit_path_printf,               0,                                  offsetof(Service, usb_function_descriptors)
+Service.USBFunctionStrings,              config_parse_unit_path_printf,               0,                                  offsetof(Service, usb_function_strings)
+Service.OOMPolicy,                       config_parse_oom_policy,                     0,                                  offsetof(Service, oom_policy)
 EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 m4_dnl
-Socket.ListenStream,             config_parse_socket_listen,         SOCKET_SOCKET,                 0
-Socket.ListenDatagram,           config_parse_socket_listen,         SOCKET_SOCKET,                 0
-Socket.ListenSequentialPacket,   config_parse_socket_listen,         SOCKET_SOCKET,                 0
-Socket.ListenFIFO,               config_parse_socket_listen,         SOCKET_FIFO,                   0
-Socket.ListenNetlink,            config_parse_socket_listen,         SOCKET_SOCKET,                 0
-Socket.ListenSpecial,            config_parse_socket_listen,         SOCKET_SPECIAL,                0
-Socket.ListenMessageQueue,       config_parse_socket_listen,         SOCKET_MQUEUE,                 0
-Socket.ListenUSBFunction,        config_parse_socket_listen,         SOCKET_USB_FUNCTION,           0
-Socket.SocketProtocol,           config_parse_socket_protocol,       0,                             offsetof(Socket, socket_protocol)
-Socket.BindIPv6Only,             config_parse_socket_bind,           0,                             offsetof(Socket, bind_ipv6_only)
-Socket.Backlog,                  config_parse_unsigned,              0,                             offsetof(Socket, backlog)
-Socket.BindToDevice,             config_parse_socket_bindtodevice,   0,                             0
-Socket.ExecStartPre,             config_parse_exec,                  SOCKET_EXEC_START_PRE,         offsetof(Socket, exec_command)
-Socket.ExecStartPost,            config_parse_exec,                  SOCKET_EXEC_START_POST,        offsetof(Socket, exec_command)
-Socket.ExecStopPre,              config_parse_exec,                  SOCKET_EXEC_STOP_PRE,          offsetof(Socket, exec_command)
-Socket.ExecStopPost,             config_parse_exec,                  SOCKET_EXEC_STOP_POST,         offsetof(Socket, exec_command)
-Socket.TimeoutSec,               config_parse_sec_fix_0,             0,                             offsetof(Socket, timeout_usec)
-Socket.SocketUser,               config_parse_user_group_compat,     0,                             offsetof(Socket, user)
-Socket.SocketGroup,              config_parse_user_group_compat,     0,                             offsetof(Socket, group)
-Socket.SocketMode,               config_parse_mode,                  0,                             offsetof(Socket, socket_mode)
-Socket.DirectoryMode,            config_parse_mode,                  0,                             offsetof(Socket, directory_mode)
-Socket.Accept,                   config_parse_bool,                  0,                             offsetof(Socket, accept)
-Socket.FlushPending,             config_parse_bool,                  0,                             offsetof(Socket, flush_pending)
-Socket.Writable,                 config_parse_bool,                  0,                             offsetof(Socket, writable)
-Socket.MaxConnections,           config_parse_unsigned,              0,                             offsetof(Socket, max_connections)
-Socket.MaxConnectionsPerSource,  config_parse_unsigned,              0,                             offsetof(Socket, max_connections_per_source)
-Socket.KeepAlive,                config_parse_bool,                  0,                             offsetof(Socket, keep_alive)
-Socket.KeepAliveTimeSec,         config_parse_sec,                   0,                             offsetof(Socket, keep_alive_time)
-Socket.KeepAliveIntervalSec,     config_parse_sec,                   0,                             offsetof(Socket, keep_alive_interval)
-Socket.KeepAliveProbes,          config_parse_unsigned,              0,                             offsetof(Socket, keep_alive_cnt)
-Socket.DeferAcceptSec,           config_parse_sec,                   0,                             offsetof(Socket, defer_accept)
-Socket.NoDelay,                  config_parse_bool,                  0,                             offsetof(Socket, no_delay)
-Socket.Priority,                 config_parse_int,                   0,                             offsetof(Socket, priority)
-Socket.ReceiveBuffer,            config_parse_iec_size,              0,                             offsetof(Socket, receive_buffer)
-Socket.SendBuffer,               config_parse_iec_size,              0,                             offsetof(Socket, send_buffer)
-Socket.IPTOS,                    config_parse_ip_tos,                0,                             offsetof(Socket, ip_tos)
-Socket.IPTTL,                    config_parse_int,                   0,                             offsetof(Socket, ip_ttl)
-Socket.Mark,                     config_parse_int,                   0,                             offsetof(Socket, mark)
-Socket.PipeSize,                 config_parse_iec_size,              0,                             offsetof(Socket, pipe_size)
-Socket.FreeBind,                 config_parse_bool,                  0,                             offsetof(Socket, free_bind)
-Socket.Transparent,              config_parse_bool,                  0,                             offsetof(Socket, transparent)
-Socket.Broadcast,                config_parse_bool,                  0,                             offsetof(Socket, broadcast)
-Socket.PassCredentials,          config_parse_bool,                  0,                             offsetof(Socket, pass_cred)
-Socket.PassSecurity,             config_parse_bool,                  0,                             offsetof(Socket, pass_sec)
-Socket.PassPacketInfo,           config_parse_bool,                  0,                             offsetof(Socket, pass_pktinfo)
-Socket.TCPCongestion,            config_parse_string,                0,                             offsetof(Socket, tcp_congestion)
-Socket.ReusePort,                config_parse_bool,                  0,                             offsetof(Socket, reuse_port)
-Socket.MessageQueueMaxMessages,  config_parse_long,                  0,                             offsetof(Socket, mq_maxmsg)
-Socket.MessageQueueMessageSize,  config_parse_long,                  0,                             offsetof(Socket, mq_msgsize)
-Socket.RemoveOnStop,             config_parse_bool,                  0,                             offsetof(Socket, remove_on_stop)
-Socket.Symlinks,                 config_parse_unit_path_strv_printf, 0,                             offsetof(Socket, symlinks)
-Socket.FileDescriptorName,       config_parse_fdname,                0,                             0
-Socket.Service,                  config_parse_socket_service,        0,                             0
-Socket.TriggerLimitIntervalSec,  config_parse_sec,                   0,                             offsetof(Socket, trigger_limit.interval)
-Socket.TriggerLimitBurst,        config_parse_unsigned,              0,                             offsetof(Socket, trigger_limit.burst)
+Socket.ListenStream,                     config_parse_socket_listen,                  SOCKET_SOCKET,                      0
+Socket.ListenDatagram,                   config_parse_socket_listen,                  SOCKET_SOCKET,                      0
+Socket.ListenSequentialPacket,           config_parse_socket_listen,                  SOCKET_SOCKET,                      0
+Socket.ListenFIFO,                       config_parse_socket_listen,                  SOCKET_FIFO,                        0
+Socket.ListenNetlink,                    config_parse_socket_listen,                  SOCKET_SOCKET,                      0
+Socket.ListenSpecial,                    config_parse_socket_listen,                  SOCKET_SPECIAL,                     0
+Socket.ListenMessageQueue,               config_parse_socket_listen,                  SOCKET_MQUEUE,                      0
+Socket.ListenUSBFunction,                config_parse_socket_listen,                  SOCKET_USB_FUNCTION,                0
+Socket.SocketProtocol,                   config_parse_socket_protocol,                0,                                  offsetof(Socket, socket_protocol)
+Socket.BindIPv6Only,                     config_parse_socket_bind,                    0,                                  offsetof(Socket, bind_ipv6_only)
+Socket.Backlog,                          config_parse_unsigned,                       0,                                  offsetof(Socket, backlog)
+Socket.BindToDevice,                     config_parse_socket_bindtodevice,            0,                                  0
+Socket.ExecStartPre,                     config_parse_exec,                           SOCKET_EXEC_START_PRE,              offsetof(Socket, exec_command)
+Socket.ExecStartPost,                    config_parse_exec,                           SOCKET_EXEC_START_POST,             offsetof(Socket, exec_command)
+Socket.ExecStopPre,                      config_parse_exec,                           SOCKET_EXEC_STOP_PRE,               offsetof(Socket, exec_command)
+Socket.ExecStopPost,                     config_parse_exec,                           SOCKET_EXEC_STOP_POST,              offsetof(Socket, exec_command)
+Socket.TimeoutSec,                       config_parse_sec_fix_0,                      0,                                  offsetof(Socket, timeout_usec)
+Socket.SocketUser,                       config_parse_user_group_compat,              0,                                  offsetof(Socket, user)
+Socket.SocketGroup,                      config_parse_user_group_compat,              0,                                  offsetof(Socket, group)
+Socket.SocketMode,                       config_parse_mode,                           0,                                  offsetof(Socket, socket_mode)
+Socket.DirectoryMode,                    config_parse_mode,                           0,                                  offsetof(Socket, directory_mode)
+Socket.Accept,                           config_parse_bool,                           0,                                  offsetof(Socket, accept)
+Socket.FlushPending,                     config_parse_bool,                           0,                                  offsetof(Socket, flush_pending)
+Socket.Writable,                         config_parse_bool,                           0,                                  offsetof(Socket, writable)
+Socket.MaxConnections,                   config_parse_unsigned,                       0,                                  offsetof(Socket, max_connections)
+Socket.MaxConnectionsPerSource,          config_parse_unsigned,                       0,                                  offsetof(Socket, max_connections_per_source)
+Socket.KeepAlive,                        config_parse_bool,                           0,                                  offsetof(Socket, keep_alive)
+Socket.KeepAliveTimeSec,                 config_parse_sec,                            0,                                  offsetof(Socket, keep_alive_time)
+Socket.KeepAliveIntervalSec,             config_parse_sec,                            0,                                  offsetof(Socket, keep_alive_interval)
+Socket.KeepAliveProbes,                  config_parse_unsigned,                       0,                                  offsetof(Socket, keep_alive_cnt)
+Socket.DeferAcceptSec,                   config_parse_sec,                            0,                                  offsetof(Socket, defer_accept)
+Socket.NoDelay,                          config_parse_bool,                           0,                                  offsetof(Socket, no_delay)
+Socket.Priority,                         config_parse_int,                            0,                                  offsetof(Socket, priority)
+Socket.ReceiveBuffer,                    config_parse_iec_size,                       0,                                  offsetof(Socket, receive_buffer)
+Socket.SendBuffer,                       config_parse_iec_size,                       0,                                  offsetof(Socket, send_buffer)
+Socket.IPTOS,                            config_parse_ip_tos,                         0,                                  offsetof(Socket, ip_tos)
+Socket.IPTTL,                            config_parse_int,                            0,                                  offsetof(Socket, ip_ttl)
+Socket.Mark,                             config_parse_int,                            0,                                  offsetof(Socket, mark)
+Socket.PipeSize,                         config_parse_iec_size,                       0,                                  offsetof(Socket, pipe_size)
+Socket.FreeBind,                         config_parse_bool,                           0,                                  offsetof(Socket, free_bind)
+Socket.Transparent,                      config_parse_bool,                           0,                                  offsetof(Socket, transparent)
+Socket.Broadcast,                        config_parse_bool,                           0,                                  offsetof(Socket, broadcast)
+Socket.PassCredentials,                  config_parse_bool,                           0,                                  offsetof(Socket, pass_cred)
+Socket.PassSecurity,                     config_parse_bool,                           0,                                  offsetof(Socket, pass_sec)
+Socket.PassPacketInfo,                   config_parse_bool,                           0,                                  offsetof(Socket, pass_pktinfo)
+Socket.TCPCongestion,                    config_parse_string,                         0,                                  offsetof(Socket, tcp_congestion)
+Socket.ReusePort,                        config_parse_bool,                           0,                                  offsetof(Socket, reuse_port)
+Socket.MessageQueueMaxMessages,          config_parse_long,                           0,                                  offsetof(Socket, mq_maxmsg)
+Socket.MessageQueueMessageSize,          config_parse_long,                           0,                                  offsetof(Socket, mq_msgsize)
+Socket.RemoveOnStop,                     config_parse_bool,                           0,                                  offsetof(Socket, remove_on_stop)
+Socket.Symlinks,                         config_parse_unit_path_strv_printf,          0,                                  offsetof(Socket, symlinks)
+Socket.FileDescriptorName,               config_parse_fdname,                         0,                                  0
+Socket.Service,                          config_parse_socket_service,                 0,                                  0
+Socket.TriggerLimitIntervalSec,          config_parse_sec,                            0,                                  offsetof(Socket, trigger_limit.interval)
+Socket.TriggerLimitBurst,                config_parse_unsigned,                       0,                                  offsetof(Socket, trigger_limit.burst)
 m4_ifdef(`ENABLE_SMACK',
-`Socket.SmackLabel,              config_parse_unit_string_printf,    0,                             offsetof(Socket, smack)
-Socket.SmackLabelIPIn,           config_parse_unit_string_printf,    0,                             offsetof(Socket, smack_ip_in)
-Socket.SmackLabelIPOut,          config_parse_unit_string_printf,    0,                             offsetof(Socket, smack_ip_out)',
-`Socket.SmackLabel,              config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-Socket.SmackLabelIPIn,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
-Socket.SmackLabelIPOut,          config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
+`Socket.SmackLabel,                      config_parse_unit_string_printf,             0,                                  offsetof(Socket, smack)
+Socket.SmackLabelIPIn,                   config_parse_unit_string_printf,             0,                                  offsetof(Socket, smack_ip_in)
+Socket.SmackLabelIPOut,                  config_parse_unit_string_printf,             0,                                  offsetof(Socket, smack_ip_out)',
+`Socket.SmackLabel,                      config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+Socket.SmackLabelIPIn,                   config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
+Socket.SmackLabelIPOut,                  config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
 m4_ifdef(`HAVE_SELINUX',
-`Socket.SELinuxContextFromNet,   config_parse_bool,                  0,                             offsetof(Socket, selinux_context_from_net)',
-`Socket.SELinuxContextFromNet,   config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
+`Socket.SELinuxContextFromNet,           config_parse_bool,                           0,                                  offsetof(Socket, selinux_context_from_net)',
+`Socket.SELinuxContextFromNet,           config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0')
 EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
 m4_dnl
-Mount.What,                      config_parse_unit_string_printf,    0,                             offsetof(Mount, parameters_fragment.what)
-Mount.Where,                     config_parse_unit_path_printf,      0,                             offsetof(Mount, where)
-Mount.Options,                   config_parse_unit_string_printf,    0,                             offsetof(Mount, parameters_fragment.options)
-Mount.Type,                      config_parse_unit_string_printf,    0,                             offsetof(Mount, parameters_fragment.fstype)
-Mount.TimeoutSec,                config_parse_sec_fix_0,             0,                             offsetof(Mount, timeout_usec)
-Mount.DirectoryMode,             config_parse_mode,                  0,                             offsetof(Mount, directory_mode)
-Mount.SloppyOptions,             config_parse_bool,                  0,                             offsetof(Mount, sloppy_options)
-Mount.LazyUnmount,               config_parse_bool,                  0,                             offsetof(Mount, lazy_unmount)
-Mount.ForceUnmount,              config_parse_bool,                  0,                             offsetof(Mount, force_unmount)
-Mount.ReadWriteOnly,             config_parse_bool,                  0,                             offsetof(Mount, read_write_only)
+Mount.What,                              config_parse_unit_string_printf,             0,                                  offsetof(Mount, parameters_fragment.what)
+Mount.Where,                             config_parse_unit_path_printf,               0,                                  offsetof(Mount, where)
+Mount.Options,                           config_parse_unit_string_printf,             0,                                  offsetof(Mount, parameters_fragment.options)
+Mount.Type,                              config_parse_unit_string_printf,             0,                                  offsetof(Mount, parameters_fragment.fstype)
+Mount.TimeoutSec,                        config_parse_sec_fix_0,                      0,                                  offsetof(Mount, timeout_usec)
+Mount.DirectoryMode,                     config_parse_mode,                           0,                                  offsetof(Mount, directory_mode)
+Mount.SloppyOptions,                     config_parse_bool,                           0,                                  offsetof(Mount, sloppy_options)
+Mount.LazyUnmount,                       config_parse_bool,                           0,                                  offsetof(Mount, lazy_unmount)
+Mount.ForceUnmount,                      config_parse_bool,                           0,                                  offsetof(Mount, force_unmount)
+Mount.ReadWriteOnly,                     config_parse_bool,                           0,                                  offsetof(Mount, read_write_only)
 EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 m4_dnl
-Automount.Where,                 config_parse_unit_path_printf,      0,                             offsetof(Automount, where)
-Automount.DirectoryMode,         config_parse_mode,                  0,                             offsetof(Automount, directory_mode)
-Automount.TimeoutIdleSec,        config_parse_sec_fix_0,             0,                             offsetof(Automount, timeout_idle_usec)
+Automount.Where,                         config_parse_unit_path_printf,               0,                                  offsetof(Automount, where)
+Automount.DirectoryMode,                 config_parse_mode,                           0,                                  offsetof(Automount, directory_mode)
+Automount.TimeoutIdleSec,                config_parse_sec_fix_0,                      0,                                  offsetof(Automount, timeout_idle_usec)
 m4_dnl
-Swap.What,                       config_parse_unit_path_printf,      0,                             offsetof(Swap, parameters_fragment.what)
-Swap.Priority,                   config_parse_swap_priority,         0,                             0
-Swap.Options,                    config_parse_unit_string_printf,    0,                             offsetof(Swap, parameters_fragment.options)
-Swap.TimeoutSec,                 config_parse_sec_fix_0,             0,                             offsetof(Swap, timeout_usec)
+Swap.What,                               config_parse_unit_path_printf,               0,                                  offsetof(Swap, parameters_fragment.what)
+Swap.Priority,                           config_parse_swap_priority,                  0,                                  0
+Swap.Options,                            config_parse_unit_string_printf,             0,                                  offsetof(Swap, parameters_fragment.options)
+Swap.TimeoutSec,                         config_parse_sec_fix_0,                      0,                                  offsetof(Swap, timeout_usec)
 EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 m4_dnl
-Timer.OnCalendar,                config_parse_timer,                 TIMER_CALENDAR,                0
-Timer.OnActiveSec,               config_parse_timer,                 TIMER_ACTIVE,                  0
-Timer.OnBootSec,                 config_parse_timer,                 TIMER_BOOT,                    0
-Timer.OnStartupSec,              config_parse_timer,                 TIMER_STARTUP,                 0
-Timer.OnUnitActiveSec,           config_parse_timer,                 TIMER_UNIT_ACTIVE,             0
-Timer.OnUnitInactiveSec,         config_parse_timer,                 TIMER_UNIT_INACTIVE,           0
-Timer.OnClockChange,             config_parse_bool,                  0,                             offsetof(Timer, on_clock_change)
-Timer.OnTimezoneChange,          config_parse_bool,                  0,                             offsetof(Timer, on_timezone_change)
-Timer.Persistent,                config_parse_bool,                  0,                             offsetof(Timer, persistent)
-Timer.WakeSystem,                config_parse_bool,                  0,                             offsetof(Timer, wake_system)
-Timer.RemainAfterElapse,         config_parse_bool,                  0,                             offsetof(Timer, remain_after_elapse)
-Timer.AccuracySec,               config_parse_sec,                   0,                             offsetof(Timer, accuracy_usec)
-Timer.RandomizedDelaySec,        config_parse_sec,                   0,                             offsetof(Timer, random_usec)
-Timer.Unit,                      config_parse_trigger_unit,          0,                             0
+Timer.OnCalendar,                        config_parse_timer,                          TIMER_CALENDAR,                     0
+Timer.OnActiveSec,                       config_parse_timer,                          TIMER_ACTIVE,                       0
+Timer.OnBootSec,                         config_parse_timer,                          TIMER_BOOT,                         0
+Timer.OnStartupSec,                      config_parse_timer,                          TIMER_STARTUP,                      0
+Timer.OnUnitActiveSec,                   config_parse_timer,                          TIMER_UNIT_ACTIVE,                  0
+Timer.OnUnitInactiveSec,                 config_parse_timer,                          TIMER_UNIT_INACTIVE,                0
+Timer.OnClockChange,                     config_parse_bool,                           0,                                  offsetof(Timer, on_clock_change)
+Timer.OnTimezoneChange,                  config_parse_bool,                           0,                                  offsetof(Timer, on_timezone_change)
+Timer.Persistent,                        config_parse_bool,                           0,                                  offsetof(Timer, persistent)
+Timer.WakeSystem,                        config_parse_bool,                           0,                                  offsetof(Timer, wake_system)
+Timer.RemainAfterElapse,                 config_parse_bool,                           0,                                  offsetof(Timer, remain_after_elapse)
+Timer.AccuracySec,                       config_parse_sec,                            0,                                  offsetof(Timer, accuracy_usec)
+Timer.RandomizedDelaySec,                config_parse_sec,                            0,                                  offsetof(Timer, random_usec)
+Timer.Unit,                              config_parse_trigger_unit,                   0,                                  0
 m4_dnl
-Path.PathExists,                 config_parse_path_spec,             0,                             0
-Path.PathExistsGlob,             config_parse_path_spec,             0,                             0
-Path.PathChanged,                config_parse_path_spec,             0,                             0
-Path.PathModified,               config_parse_path_spec,             0,                             0
-Path.DirectoryNotEmpty,          config_parse_path_spec,             0,                             0
-Path.Unit,                       config_parse_trigger_unit,          0,                             0
-Path.MakeDirectory,              config_parse_bool,                  0,                             offsetof(Path, make_directory)
-Path.DirectoryMode,              config_parse_mode,                  0,                             offsetof(Path, directory_mode)
+Path.PathExists,                         config_parse_path_spec,                      0,                                  0
+Path.PathExistsGlob,                     config_parse_path_spec,                      0,                                  0
+Path.PathChanged,                        config_parse_path_spec,                      0,                                  0
+Path.PathModified,                       config_parse_path_spec,                      0,                                  0
+Path.DirectoryNotEmpty,                  config_parse_path_spec,                      0,                                  0
+Path.Unit,                               config_parse_trigger_unit,                   0,                                  0
+Path.MakeDirectory,                      config_parse_bool,                           0,                                  offsetof(Path, make_directory)
+Path.DirectoryMode,                      config_parse_mode,                           0,                                  offsetof(Path, directory_mode)
 m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Slice)m4_dnl
 m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl
-Scope.RuntimeMaxSec,             config_parse_sec,                   0,                             offsetof(Scope, runtime_max_usec)
-Scope.TimeoutStopSec,            config_parse_sec,                   0,                             offsetof(Scope, timeout_stop_usec)
+Scope.RuntimeMaxSec,                     config_parse_sec,                            0,                                  offsetof(Scope, runtime_max_usec)
+Scope.TimeoutStopSec,                    config_parse_sec,                            0,                                  offsetof(Scope, timeout_stop_usec)
 m4_dnl The [Install] section is ignored here.
-Install.Alias,                   NULL,                               0,                             0
-Install.WantedBy,                NULL,                               0,                             0
-Install.RequiredBy,              NULL,                               0,                             0
-Install.Also,                    NULL,                               0,                             0
-Install.DefaultInstance,         NULL,                               0,                             0
+Install.Alias,                           NULL,                                        0,                                  0
+Install.WantedBy,                        NULL,                                        0,                                  0
+Install.RequiredBy,                      NULL,                                        0,                                  0
+Install.Also,                            NULL,                                        0,                                  0
+Install.DefaultInstance,                 NULL,                                        0,                                  0
index 480da2c0dd15aeb2e87ae7cf6841b865cd04168f..60c9a5f03a94fed093a1f1521c2eb45add4b9ff5 100644 (file)
@@ -26,6 +26,7 @@
 #include "capability-util.h"
 #include "cgroup-setup.h"
 #include "conf-parser.h"
+#include "core-varlink.h"
 #include "cpu-set-util.h"
 #include "env-util.h"
 #include "errno-list.h"
@@ -1349,6 +1350,44 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
         return 0;
 }
 
+int config_parse_exec_mount_apivfs(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) {
+
+        ExecContext *c = data;
+        int k;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                c->mount_apivfs_set = false;
+                c->mount_apivfs = false;
+                return 0;
+        }
+
+        k = parse_boolean(rvalue);
+        if (k < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, k,
+                           "Failed to parse boolean value, ignoring: %s",
+                           rvalue);
+                return 0;
+        }
+
+        c->mount_apivfs_set = true;
+        c->mount_apivfs = k;
+        return 0;
+}
+
 int config_parse_numa_mask(const char *unit,
                            const char *filename,
                            unsigned line,
@@ -3774,6 +3813,76 @@ int config_parse_delegate(
         return 0;
 }
 
+int config_parse_managed_oom_mode(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+        ManagedOOMMode *mode = data, m;
+        UnitType t;
+
+        t = unit_name_to_type(unit);
+        assert(t != _UNIT_TYPE_INVALID);
+
+        if (!unit_vtable[t]->can_set_managed_oom)
+                return log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is not supported for this unit type, ignoring.", lvalue);
+
+        if (isempty(rvalue)) {
+                *mode = MANAGED_OOM_AUTO;
+                return 0;
+        }
+
+        m = managed_oom_mode_from_string(rvalue);
+        if (m < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid syntax, ignoring: %s", rvalue);
+                return 0;
+        }
+        *mode = m;
+        return 0;
+}
+
+int config_parse_managed_oom_mem_pressure_limit(
+                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 *limit = data;
+        UnitType t;
+        int r;
+
+        t = unit_name_to_type(unit);
+        assert(t != _UNIT_TYPE_INVALID);
+
+        if (!unit_vtable[t]->can_set_managed_oom)
+                return log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is not supported for this unit type, ignoring.", lvalue);
+
+        if (isempty(rvalue)) {
+                *limit = 0;
+                return 0;
+        }
+
+        r = parse_percent(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse limit percent value, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        *limit = r;
+        return 0;
+}
+
 int config_parse_device_allow(
                 const char *unit,
                 const char *filename,
index 3504227cae7be42c7f0bdaa4b7ae1edfc57adeff..fa4c1fb1a01855fea20d2e09e8339a14802db748 100644 (file)
@@ -43,6 +43,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_io_priority);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_apivfs);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
 CONFIG_PARSER_PROTOTYPE(config_parse_root_image_options);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
@@ -75,6 +76,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
 CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
 CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
 CONFIG_PARSER_PROTOTYPE(config_parse_delegate);
+CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mem_pressure_limit);
 CONFIG_PARSER_PROTOTYPE(config_parse_device_policy);
 CONFIG_PARSER_PROTOTYPE(config_parse_device_allow);
 CONFIG_PARSER_PROTOTYPE(config_parse_io_device_latency);
index 6aecd36fe6c087802602527a4388b70f4a310fe3..c55e0b53212389ac30ffb6b321b1108a74317c5a 100644 (file)
@@ -11,6 +11,7 @@
 #include "fd-util.h"
 #include "fs-util.h"
 #include "id128-util.h"
+#include "io-util.h"
 #include "log.h"
 #include "machine-id-setup.h"
 #include "macro.h"
@@ -86,7 +87,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
         return 0;
 }
 
-int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
+int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_id, sd_id128_t *ret) {
         const char *etc_machine_id, *run_machine_id;
         _cleanup_close_ int fd = -1;
         bool writable;
@@ -143,13 +144,31 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
                 if (ftruncate(fd, 0) < 0)
                         return log_error_errno(errno, "Failed to truncate %s: %m", etc_machine_id);
 
-                if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0)
-                        goto finish;
+                /* If the caller requested a transient machine-id, write the string "uninitialized\n" to
+                 * disk and overmount it with a transient file.
+                 *
+                 * Otherwise write the machine-id directly to disk. */
+                if (force_transient) {
+                        r = loop_write(fd, "uninitialized\n", strlen("uninitialized\n"), false);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to write uninitialized %s: %m", etc_machine_id);
+
+                        r = fsync_full(fd);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
+                } else {
+                        r = id128_write_fd(fd, ID128_PLAIN, machine_id, true);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
+                        else
+                                goto finish;
+                }
         }
 
         fd = safe_close(fd);
 
-        /* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */
+        /* Hmm, we couldn't or shouldn't write the machine-id to /etc?
+         * So let's write it to /run/machine-id as a replacement */
 
         run_machine_id = prefix_roota(root, "/run/machine-id");
 
@@ -167,7 +186,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
                 return r;
         }
 
-        log_info("Installed transient %s file.", etc_machine_id);
+        log_full(force_transient ? LOG_DEBUG : LOG_INFO, "Installed transient %s file.", etc_machine_id);
 
         /* Mark the mount read-only */
         r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
@@ -183,10 +202,22 @@ finish:
 
 int machine_id_commit(const char *root) {
         _cleanup_close_ int fd = -1, initial_mntns_fd = -1;
-        const char *etc_machine_id;
+        const char *etc_machine_id, *sync_path;
         sd_id128_t id;
         int r;
 
+        /* Before doing anything, sync everything to ensure any changes by first-boot units are persisted.
+         *
+         * First, explicitly sync the file systems we care about and check if it worked. */
+        FOREACH_STRING(sync_path, "/etc/", "/var/") {
+                r = syncfs_path(AT_FDCWD, sync_path);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot sync %s: %m", sync_path);
+        }
+
+        /* Afterwards, sync() the rest too, but we can't check the return value for these. */
+        sync();
+
         /* Replaces a tmpfs bind mount of /etc/machine-id by a proper file, atomically. For this, the umount is removed
          * in a mount namespace, a new file is created at the right place. Afterwards the mount is also removed in the
          * original mount namespace, thus revealing the file that was just created. */
index d6ac62a88243f3f763ccd9706a5242ee00426f84..e207ccf9c11a578de9a836021eef0c274bd7c685 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdbool.h>
+
 int machine_id_commit(const char *root);
-int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);
+int machine_id_setup(const char *root, bool force_transient, sd_id128_t requested, sd_id128_t *ret);
index f957217eaaa1ce07417daea8c24d2feff6b8aacb..728e1578b1ae52bf521a98e2994a45ee063c6e63 100644 (file)
@@ -1064,13 +1064,11 @@ static int parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option code.");
                 }
 
-        if (optind < argc && getpid_cached() != 1) {
+        if (optind < argc && getpid_cached() != 1)
                 /* Hmm, when we aren't run as init system
                  * let's complain about excess arguments */
-
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Excess arguments.");
-        }
 
         return 0;
 }
@@ -1564,7 +1562,7 @@ static void initialize_clock(void) {
                 else
                         log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
 
-        } else if (!in_initrd()) {
+        } else if (!in_initrd())
                 /*
                  * Do a dummy very first call to seal the kernel's time warp magic.
                  *
@@ -1577,7 +1575,6 @@ static void initialize_clock(void) {
                  * be treated as UTC that way.
                  */
                 (void) clock_reset_timewarp();
-        }
 
         r = clock_apply_epoch();
         if (r < 0)
@@ -2004,15 +2001,26 @@ static void log_execution_mode(bool *ret_first_boot) {
                         *ret_first_boot = false;
                         log_info("Running in initial RAM disk.");
                 } else {
-                        /* Let's check whether we are in first boot, i.e. whether /etc is still unpopulated. We use
-                         * /etc/machine-id as flag file, for this: if it exists we assume /etc is populated, if it
-                         * doesn't it's unpopulated. This allows container managers and installers to provision a
-                         * couple of files already. If the container manager wants to provision the machine ID itself
-                         * it should pass $container_uuid to PID 1. */
-
-                        *ret_first_boot = access("/etc/machine-id", F_OK) < 0;
-                        if (*ret_first_boot)
-                                log_info("Running with unpopulated /etc.");
+                        int r;
+                        _cleanup_free_ char *id_text = NULL;
+
+                        /* Let's check whether we are in first boot.  We use /etc/machine-id as flag file
+                         * for this: If it is missing or contains the value "uninitialized", this is the
+                         * first boot.  In any other case, it is not.  This allows container managers and
+                         * installers to provision a couple of files already.  If the container manager
+                         * wants to provision the machine ID itself it should pass $container_uuid to PID 1. */
+
+                        r = read_one_line_file("/etc/machine-id", &id_text);
+                        if (r < 0 || streq(id_text, "uninitialized")) {
+                                if (r < 0 && r != -ENOENT)
+                                        log_warning_errno(r, "Unexpected error while reading /etc/machine-id, ignoring: %m");
+
+                                *ret_first_boot = true;
+                                log_info("Detected first boot.");
+                        } else {
+                                *ret_first_boot = false;
+                                log_debug("Detected initialized system, this is not the first boot.");
+                        }
                 }
         } else {
                 if (DEBUG_LOGGING) {
@@ -2029,6 +2037,7 @@ static void log_execution_mode(bool *ret_first_boot) {
 
 static int initialize_runtime(
                 bool skip_setup,
+                bool first_boot,
                 struct rlimit *saved_rlimit_nofile,
                 struct rlimit *saved_rlimit_memlock,
                 const char **ret_error_message) {
@@ -2062,7 +2071,8 @@ static int initialize_runtime(
 
                         status_welcome();
                         hostname_setup();
-                        machine_id_setup(NULL, arg_machine_id, NULL);
+                        /* Force transient machine-id on first boot. */
+                        machine_id_setup(NULL, first_boot, arg_machine_id, NULL);
                         (void) loopback_setup();
                         bump_unix_max_dgram_qlen();
                         bump_file_max_and_nr_open();
@@ -2790,6 +2800,7 @@ int main(int argc, char *argv[]) {
         log_execution_mode(&first_boot);
 
         r = initialize_runtime(skip_setup,
+                               first_boot,
                                &saved_rlimit_nofile,
                                &saved_rlimit_memlock,
                                &error_message);
index d85d938e7bab25f665bc3e4194da3b671636b2aa..bf3a3c64f09c609cb653a659b872b81364f0d079 100644 (file)
@@ -2578,6 +2578,11 @@ static int manager_dispatch_sigchld(sd_event_source *source, void *userdata) {
                          * We only do this for the cgroup the PID belonged to. */
                         (void) unit_check_oom(u1);
 
+                        /* This only logs for now. In the future when the interface for kills/notifications
+                         * is more stable we can extend service results table similar to how kernel oom kills
+                         * are managed. */
+                        (void) unit_check_oomd_kill(u1);
+
                         manager_invoke_sigchld_event(m, u1, &si);
                 }
                 if (u2)
@@ -3492,6 +3497,24 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
         assert(m);
         assert(f);
 
+        if (DEBUG_LOGGING) {
+                if (fdset_isempty(fds))
+                        log_debug("No file descriptors passed");
+                else {
+                        int fd;
+
+                        FDSET_FOREACH(fd, fds) {
+                                _cleanup_free_ char *fn = NULL;
+
+                                r = fd_get_path(fd, &fn);
+                                if (r < 0)
+                                        log_debug_errno(r, "Received serialized fd %i → %m", fd);
+                                else
+                                        log_debug("Received serialized fd %i → %s", fd, strna(fn));
+                        }
+                }
+        }
+
         log_debug("Deserializing state...");
 
         /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
index 9e98b31c4bd1085d55e37a5cdb1e60f2498a00bf..073cc74a85398e95926fe3ef4c1a4d57aa0e0f9b 100644 (file)
@@ -434,6 +434,8 @@ struct Manager {
         bool honor_device_enumeration;
 
         VarlinkServer *varlink_server;
+        /* Only systemd-oomd should be using this to subscribe to changes in ManagedOOM settings */
+        Varlink *managed_oom_varlink_request;
 };
 
 static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
index e1ecb448ea24ade2a1e2a3583abd3637dca51987..f745df7c95d2185a251464e7b3134d26fb669585 100644 (file)
@@ -112,17 +112,6 @@ static const MountPoint mount_table[] = {
           NULL,          MNT_NONE,                  },
 };
 
-/* These are API file systems that might be mounted by other software,
- * we just list them here so that we know that we should ignore them */
-
-static const char ignore_paths[] =
-        /* SELinux file systems */
-        "/sys/fs/selinux\0"
-        /* Container bind mounts */
-        "/proc/sys\0"
-        "/dev/console\0"
-        "/proc/kmsg\0";
-
 bool mount_point_is_api(const char *path) {
         unsigned i;
 
@@ -137,12 +126,26 @@ bool mount_point_is_api(const char *path) {
 }
 
 bool mount_point_ignore(const char *path) {
+
         const char *i;
 
-        NULSTR_FOREACH(i, ignore_paths)
+        /* These are API file systems that might be mounted by other software, we just list them here so that
+         * we know that we should ignore them. */
+        FOREACH_STRING(i,
+                       /* SELinux file systems */
+                       "/sys/fs/selinux",
+                       /* Container bind mounts */
+                       "/dev/console",
+                       "/proc/kmsg",
+                       "/proc/sys",
+                       "/proc/sys/kernel/random/boot_id")
                 if (path_equal(path, i))
                         return true;
 
+        if (path_startswith(path, "/run/host")) /* All mounts passed in from the container manager are
+                                                 * something we better ignore. */
+                return true;
+
         return false;
 }
 
index 92df97c4fb2c700040210a32595262c72679c27e..05bd4da154455ff5b2fb02a1a08479c6fffd33d6 100644 (file)
@@ -1618,13 +1618,12 @@ int setup_namespace(
                 if (r < 0)
                         goto finish;
 
-                if (ns_info->private_dev) {
+                if (ns_info->private_dev)
                         *(m++) = (MountEntry) {
                                 .path_const = "/dev",
                                 .mode = PRIVATE_DEV,
                                 .flags = DEV_MOUNT_OPTIONS,
                         };
-                }
 
                 if (ns_info->protect_kernel_tunables) {
                         r = append_static_mounts(&m,
@@ -1653,12 +1652,11 @@ int setup_namespace(
                                 goto finish;
                 }
 
-                if (ns_info->protect_control_groups) {
+                if (ns_info->protect_control_groups)
                         *(m++) = (MountEntry) {
                                 .path_const = "/sys/fs/cgroup",
                                 .mode = READONLY,
                         };
-                }
 
                 r = append_protect_home(&m, ns_info->protect_home, ns_info->ignore_protect_paths);
                 if (r < 0)
index 42c51b08651641664183950ea874c110dbc1139c..540c83ba451b6ab75dc162753f410123276c02e4 100644 (file)
@@ -621,6 +621,7 @@ const UnitVTable scope_vtable = {
         .can_delegate = true,
         .can_fail = true,
         .once_only = true,
+        .can_set_managed_oom = true,
 
         .init = scope_init,
         .load = scope_load,
index 40da8dd0e5c03e5df34135c71764863265dcfa92..8c67352ddb478ab5d9d750511b8549a84688b921 100644 (file)
@@ -96,10 +96,9 @@ int mac_selinux_setup(bool *loaded_policy) {
                 log_open();
 
                 if (enforce > 0) {
-                        if (!initialized) {
-                                log_emergency("Failed to load SELinux policy.");
-                                return -EIO;
-                        }
+                        if (!initialized)
+                                return log_emergency_errno(SYNTHETIC_ERRNO(EIO),
+                                                           "Failed to load SELinux policy.");
 
                         log_warning("Failed to load new SELinux policy. Continuing with old policy.");
                 } else
index 863b6755b1d6068d4b5fff4ca071efd5051e7641..9d834d4069dbe04c719f511eb7ce91a0c92fcddf 100644 (file)
@@ -4201,7 +4201,7 @@ static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
         else
                 log_unit_debug(u, "D-Bus name %s now not owned by anyone.", s->bus_name);
 
-        s->bus_name_good = !!new_owner;
+        s->bus_name_good = new_owner;
 
         /* Track the current owner, so we can reconstruct changes after a daemon reload */
         r = free_and_strdup(&s->bus_name_owner, new_owner);
@@ -4533,6 +4533,7 @@ const UnitVTable service_vtable = {
         .can_transient = true,
         .can_delegate = true,
         .can_fail = true,
+        .can_set_managed_oom = true,
 
         .init = service_init,
         .done = service_done,
index 49541aacab452f97048a4a80d0e03e1f604364a1..36e5d6a40fdd38d553a50b8f1101c3d86266f636 100644 (file)
@@ -435,6 +435,7 @@ const UnitVTable slice_vtable = {
         .private_section = "Slice",
 
         .can_transient = true,
+        .can_set_managed_oom = true,
 
         .init = slice_init,
         .load = slice_load,
index be7d364084dd305e742c20a7da98d10366bbb15f..f71fa34300b8a3b5a86e44755d2be29fdc46120a 100644 (file)
@@ -526,8 +526,7 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
         assert(fd >= 0);
         assert(s);
 
-        r = getpeername(fd, &sa.peer.sa, &salen);
-        if (r < 0)
+        if (getpeername(fd, &sa.peer.sa, &salen) < 0)
                 return log_unit_error_errno(UNIT(s), errno, "getpeername failed: %m");
 
         if (!IN_SET(sa.peer.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
index 3af9f99830402c336cdd9dc397d194e0db9b1f02..c0554649dea2598706bab2ba51b4838ea7affe88 100644 (file)
@@ -80,9 +80,9 @@ modulesloaddir=${modules_load_dir}
 catalog_dir=/usr/lib/systemd/catalog
 catalogdir=${catalog_dir}
 
-system_uid_max=@systemuidmax@
+system_uid_max=@SYSTEM_UID_MAX@
 systemuidmax=${system_uid_max}
-system_gid_max=@systemgidmax@
+system_gid_max=@SYSTEM_GID_MAX@
 systemgidmax=${system_gid_max}
 
 dynamic_uid_min=@dynamicuidmin@
index c3d7d24eccdf369ff9301836d6b8977596f0d841..680f4c569bd93f718446b36ebdadee4399a91af7 100644 (file)
@@ -15,6 +15,7 @@
 #include "bus-util.h"
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
+#include "core-varlink.h"
 #include "dbus-unit.h"
 #include "dbus.h"
 #include "dropin.h"
@@ -1573,6 +1574,31 @@ static int unit_add_mount_dependencies(Unit *u) {
         return 0;
 }
 
+static int unit_add_oomd_dependencies(Unit *u) {
+        CGroupContext *c;
+        bool wants_oomd;
+        int r;
+
+        assert(u);
+
+        if (!u->default_dependencies)
+                return 0;
+
+        c = unit_get_cgroup_context(u);
+        if (!c)
+                return 0;
+
+        wants_oomd = (c->moom_swap == MANAGED_OOM_KILL || c->moom_mem_pressure == MANAGED_OOM_KILL);
+        if (!wants_oomd)
+                return 0;
+
+        r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, "systemd-oomd.service", true, UNIT_DEPENDENCY_FILE);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 static int unit_add_startup_units(Unit *u) {
         CGroupContext *c;
 
@@ -1633,6 +1659,10 @@ int unit_load(Unit *u) {
                 if (r < 0)
                         goto fail;
 
+                r = unit_add_oomd_dependencies(u);
+                if (r < 0)
+                        goto fail;
+
                 r = unit_add_startup_units(u);
                 if (r < 0)
                         goto fail;
@@ -1654,6 +1684,7 @@ int unit_load(Unit *u) {
 
         unit_add_to_dbus_queue(unit_follow_merge(u));
         unit_add_to_gc_queue(u);
+        (void) manager_varlink_send_managed_oom_update(u);
 
         return 0;
 
@@ -2592,6 +2623,18 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
          * 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 systemd-oomd on the property/state change */
+        if (os != ns) {
+                /* Always send an update if the unit is going into an inactive state so systemd-oomd knows to stop
+                 * monitoring.
+                 * Also send an update whenever the unit goes active; this is to handle a case where an override file
+                 * sets one of the ManagedOOM*= properties to "kill", then later removes it. systemd-oomd needs to
+                 * know to stop monitoring when the unit changes from "kill" -> "auto" on daemon-reload, but we don't
+                 * have the information on the property. Thus, indiscriminately send an update. */
+                if (UNIT_IS_INACTIVE_OR_FAILED(ns) || UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                        (void) manager_varlink_send_managed_oom_update(u);
+        }
+
         /* Update timestamps for state changes */
         if (!MANAGER_IS_RELOADING(m)) {
                 dual_timestamp_get(&u->state_change_timestamp);
@@ -3020,6 +3063,9 @@ int unit_add_dependency(
         };
         Unit *original_u = u, *original_other = other;
         int r;
+        /* Helper to know whether sending a notification is necessary or not:
+         * if the dependency is already there, no need to notify! */
+        bool noop = true;
 
         assert(u);
         assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
@@ -3057,24 +3103,33 @@ int unit_add_dependency(
         r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0);
         if (r < 0)
                 return r;
+        else if (r > 0)
+                noop = false;
 
         if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) {
                 r = unit_add_dependency_hashmap(other->dependencies + inverse_table[d], u, 0, mask);
                 if (r < 0)
                         return r;
+                else if (r > 0)
+                        noop = false;
         }
 
         if (add_reference) {
                 r = unit_add_dependency_hashmap(u->dependencies + UNIT_REFERENCES, other, mask, 0);
                 if (r < 0)
                         return r;
+                else if (r > 0)
+                        noop = false;
 
                 r = unit_add_dependency_hashmap(other->dependencies + UNIT_REFERENCED_BY, u, 0, mask);
                 if (r < 0)
                         return r;
+                else if (r > 0)
+                        noop = false;
         }
 
-        unit_add_to_dbus_queue(u);
+        if (!noop)
+                unit_add_to_dbus_queue(u);
         return 0;
 }
 
@@ -3546,6 +3601,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         if (u->cpu_usage_last != NSEC_INFINITY)
                 (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
 
+        if (u->managed_oom_kill_last > 0)
+                (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
+
         if (u->oom_kill_last > 0)
                 (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
 
@@ -3791,6 +3849,14 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
 
                         continue;
 
+                } else if (streq(l, "managed-oom-kill-last")) {
+
+                        r = safe_atou64(v, &u->managed_oom_kill_last);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v);
+
+                        continue;
+
                 } else if (streq(l, "oom-kill-last")) {
 
                         r = safe_atou64(v, &u->oom_kill_last);
@@ -4255,6 +4321,19 @@ static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
         return TAKE_PTR(pid_set);
 }
 
+static int kill_common_log(pid_t pid, int signo, void *userdata) {
+        _cleanup_free_ char *comm = NULL;
+        Unit *u = userdata;
+
+        assert(u);
+
+        (void) get_process_comm(pid, &comm);
+        log_unit_info(u, "Sending signal SIG%s to process " PID_FMT " (%s) on client request.",
+                      signal_to_string(signo), pid, strna(comm));
+
+        return 1;
+}
+
 int unit_kill_common(
                 Unit *u,
                 KillWho who,
@@ -4266,34 +4345,67 @@ int unit_kill_common(
         int r = 0;
         bool killed = false;
 
+        /* This is the common implementation for explicit user-requested killing of unit processes, shared by
+         * various unit types. Do not confuse with unit_kill_context(), which is what we use when we want to
+         * stop a service ourselves. */
+
         if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
                 if (main_pid < 0)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
-                else if (main_pid == 0)
+                if (main_pid == 0)
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
         }
 
         if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
                 if (control_pid < 0)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
-                else if (control_pid == 0)
+                if (control_pid == 0)
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
         }
 
         if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
                 if (control_pid > 0) {
-                        if (kill(control_pid, signo) < 0)
-                                r = -errno;
-                        else
+                        _cleanup_free_ char *comm = NULL;
+                        (void) get_process_comm(control_pid, &comm);
+
+                        if (kill(control_pid, signo) < 0) {
+                                /* Report this failure both to the logs and to the client */
+                                sd_bus_error_set_errnof(
+                                                error, errno,
+                                                "Failed to send signal SIG%s to control process " PID_FMT " (%s): %m",
+                                                signal_to_string(signo), control_pid, strna(comm));
+                                r = log_unit_warning_errno(
+                                                u, errno,
+                                                "Failed to send signal SIG%s to control process " PID_FMT " (%s) on client request: %m",
+                                                signal_to_string(signo), control_pid, strna(comm));
+                        } else {
+                                log_unit_info(u, "Sent signal SIG%s to control process " PID_FMT " (%s) on client request.",
+                                              signal_to_string(signo), control_pid, strna(comm));
                                 killed = true;
+                        }
                 }
 
         if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
                 if (main_pid > 0) {
-                        if (kill(main_pid, signo) < 0)
-                                r = -errno;
-                        else
+                        _cleanup_free_ char *comm = NULL;
+                        (void) get_process_comm(main_pid, &comm);
+
+                        if (kill(main_pid, signo) < 0) {
+                                if (r == 0)
+                                        sd_bus_error_set_errnof(
+                                                        error, errno,
+                                                        "Failed to send signal SIG%s to main process " PID_FMT " (%s): %m",
+                                                        signal_to_string(signo), main_pid, strna(comm));
+
+                                r = log_unit_warning_errno(
+                                                u, errno,
+                                                "Failed to send signal SIG%s to main process " PID_FMT " (%s) on client request: %m",
+                                                signal_to_string(signo), main_pid, strna(comm));
+                        } else {
+                                log_unit_info(u, "Sent signal SIG%s to main process " PID_FMT " (%s) on client request.",
+                                              signal_to_string(signo), main_pid, strna(comm));
                                 killed = true;
+                        }
                 }
 
         if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path) {
@@ -4303,17 +4415,29 @@ int unit_kill_common(
                 /* Exclude the main/control pids from being killed via the cgroup */
                 pid_set = unit_pid_set(main_pid, control_pid);
                 if (!pid_set)
-                        return -ENOMEM;
+                        return log_oom();
 
-                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, NULL, NULL);
-                if (q < 0 && !IN_SET(q, -EAGAIN, -ESRCH, -ENOENT))
-                        r = q;
-                else
+                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, kill_common_log, u);
+                if (q < 0) {
+                        if (!IN_SET(q, -ESRCH, -ENOENT)) {
+                                if (r == 0)
+                                        sd_bus_error_set_errnof(
+                                                        error, q,
+                                                        "Failed to send signal SIG%s to auxiliary processes: %m",
+                                                        signal_to_string(signo));
+
+                                r = log_unit_warning_errno(
+                                                u, q,
+                                                "Failed to send signal SIG%s to auxiliary processes on client request: %m",
+                                                signal_to_string(signo));
+                        }
+                } else
                         killed = true;
         }
 
-        if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL))
-                return -ESRCH;
+        /* If the "fail" versions of the operation are requested, then complain if the set of processes we killed is empty */
+        if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_MAIN_FAIL))
+                return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No matching processes to kill");
 
         return r;
 }
@@ -4899,8 +5023,9 @@ int unit_kill_context(
         assert(u);
         assert(c);
 
-        /* Kill the processes belonging to this unit, in preparation for shutting the unit down.
-         * Returns > 0 if we killed something worth waiting for, 0 otherwise. */
+        /* Kill the processes belonging to this unit, in preparation for shutting the unit down.  Returns > 0
+         * if we killed something worth waiting for, 0 otherwise. Do not confuse with unit_kill_common()
+         * which is used for user-requested killing of unit processes. */
 
         if (c->kill_mode == KILL_NONE)
                 return 0;
@@ -5502,7 +5627,7 @@ void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) {
                         done = true;
 
                         HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
-                                if ((di.origin_mask & ~mask) == di.origin_mask)
+                                if (FLAGS_SET(~mask, di.origin_mask))
                                         continue;
                                 di.origin_mask &= ~mask;
                                 unit_update_dependency_mask(u, d, other, di);
@@ -5516,7 +5641,7 @@ void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) {
                                         UnitDependencyInfo dj;
 
                                         dj.data = hashmap_get(other->dependencies[q], u);
-                                        if ((dj.destination_mask & ~mask) == dj.destination_mask)
+                                        if (FLAGS_SET(~mask, dj.destination_mask))
                                                 continue;
                                         dj.destination_mask &= ~mask;
 
index 35873d57bc341c89dbe6bb3ec5db9187cfa2be9a..1e6d7ccf6be2612f2de92754aecce0f640d873ac 100644 (file)
@@ -260,7 +260,10 @@ typedef struct Unit {
         nsec_t cpu_usage_base;
         nsec_t cpu_usage_last; /* the most recently read value */
 
-        /* The  current counter of the oom_kill field in the memory.events cgroup attribute */
+        /* The current counter of processes sent SIGKILL by systemd-oomd */
+        uint64_t managed_oom_kill_last;
+
+        /* The current counter of the oom_kill field in the memory.events cgroup attribute */
         uint64_t oom_kill_last;
 
         /* Where the io.stat data was at the time the unit was started */
@@ -625,6 +628,9 @@ typedef struct UnitVTable {
 
         /* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
         bool gc_jobs:1;
+
+        /* True if systemd-oomd can monitor and act on this unit's recursive children's cgroup(s)  */
+        bool can_set_managed_oom:1;
 } UnitVTable;
 
 extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
index 88739ed5bccc22303924d17a8b1d4a95c29bcc8e..104a051688e57d285eec6243f4233d55c9653720 100644 (file)
@@ -46,6 +46,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util.h"
+#include "user-record.h"
 #include "user-util.h"
 
 /* The maximum size up to which we process coredumps */
@@ -352,7 +353,7 @@ static int save_external_coredump(
         if (r < 0)
                 return log_error_errno(r, "Failed to parse resource limit '%s': %m",
                                        context->meta[META_ARGV_RLIMIT]);
-        if (rlimit < page_size()) {
+        if (rlimit < page_size())
                 /* Is coredumping disabled? Then don't bother saving/processing the
                  * coredump.  Anything below PAGE_SIZE cannot give a readable coredump
                  * (the kernel uses ELF_EXEC_PAGESIZE which is not easily accessible, but
@@ -360,7 +361,6 @@ static int save_external_coredump(
                 return log_info_errno(SYNTHETIC_ERRNO(EBADSLT),
                                       "Resource limits disable core dumping for process %s (%s).",
                                       context->meta[META_ARGV_PID], context->meta[META_COMM]);
-        }
 
         process_limit = MAX(arg_process_size_max, storage_size_max());
         if (process_limit == 0)
@@ -682,7 +682,7 @@ static int change_uid_gid(const Context *context) {
         if (r < 0)
                 return r;
 
-        if (uid <= SYSTEM_UID_MAX) {
+        if (uid_is_system(uid)) {
                 const char *user = "systemd-coredump";
 
                 r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
index 02502528afe2bf3909d53742410e29f8e19c64e5..f252c8175861f0eea9929a4f51320f17e50cd308 100644 (file)
@@ -888,10 +888,9 @@ static int dump_core(int argc, char **argv, void *userdata) {
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
-        if (arg_field) {
-                log_error("Option --field/-F only makes sense with list");
-                return -EINVAL;
-        }
+        if (arg_field)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Option --field/-F only makes sense with list");
 
         r = acquire_journal(&j, argv + 1);
         if (r < 0)
@@ -943,10 +942,9 @@ static int run_debug(int argc, char **argv, void *userdata) {
         if (!debugger)
                 return -ENOMEM;
 
-        if (arg_field) {
-                log_error("Option --field/-F only makes sense with list");
-                return -EINVAL;
-        }
+        if (arg_field)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Option --field/-F only makes sense with list");
 
         r = acquire_journal(&j, argv + 1);
         if (r < 0)
@@ -971,15 +969,13 @@ static int run_debug(int argc, char **argv, void *userdata) {
         if (!exe)
                 return log_oom();
 
-        if (endswith(exe, " (deleted)")) {
-                log_error("Binary already deleted.");
-                return -ENOENT;
-        }
+        if (endswith(exe, " (deleted)"))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "Binary already deleted.");
 
-        if (!path_is_absolute(exe)) {
-                log_error("Binary is not an absolute path.");
-                return -ENOENT;
-        }
+        if (!path_is_absolute(exe))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "Binary is not an absolute path.");
 
         r = save_core(j, NULL, &path, &unlink_path);
         if (r < 0)
index 3ff50f4b6bce74f9d78c0e334ae989241a093a4b..13e9f3aedd01416133c75523e8c031865b76c93c 100644 (file)
@@ -29,6 +29,8 @@ typedef struct crypto_device {
         char *uuid;
         char *keyfile;
         char *keydev;
+        char *headerdev;
+        char *datadev;
         char *name;
         char *options;
         bool create;
@@ -48,62 +50,64 @@ STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
 
-static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) {
-        _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
+static int split_locationspec(const char *locationspec, char **ret_file, char **ret_device) {
+        _cleanup_free_ char *file = NULL, *device = NULL;
         const char *c;
 
-        assert(ret_keyfile);
-        assert(ret_keydev);
+        assert(ret_file);
+        assert(ret_device);
 
-        if (!keyspec) {
-                *ret_keyfile = *ret_keydev = NULL;
+        if (!locationspec) {
+                *ret_file = *ret_device = NULL;
                 return 0;
         }
 
-        c = strrchr(keyspec, ':');
+        c = strrchr(locationspec, ':');
         if (c) {
-                /* The keydev part has to be either an absolute path to device node (/dev/something,
+                /* The device part has to be either an absolute path to device node (/dev/something,
                  * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
-                 * specification starting with LABEL= or similar. The keyfile part has the same syntax.
+                 * specification starting with LABEL= or similar. The file part has the same syntax.
                  *
-                 * Let's try to guess if the second part looks like a keydev specification, or just part of a
+                 * Let's try to guess if the second part looks like a device specification, or just part of a
                  * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
                  * an absolute path. If we didn't get an absolute path, assume that it is just part of the
-                 * first keyfile argument. */
+                 * first file argument. */
 
-                keydev = fstab_node_to_udev_node(c + 1);
-                if (!keydev)
+                device = fstab_node_to_udev_node(c + 1);
+                if (!device)
                         return log_oom();
 
-                if (path_is_absolute(keydev))
-                        keyfile = strndup(keyspec, c-keyspec);
+                if (path_is_absolute(device))
+                        file = strndup(locationspec, c-locationspec);
                 else {
-                        log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
+                        log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
                                   "Assuming that \"%s\" is a single device specification.",
-                                  c + 1, keyspec);
-                        keydev = mfree(keydev);
+                                  c + 1, locationspec);
+                        device = mfree(device);
                         c = NULL;
                 }
         }
 
         if (!c)
-                /* No keydev specified */
-                keyfile = strdup(keyspec);
+                /* No device specified */
+                file = strdup(locationspec);
 
-        if (!keyfile)
+        if (!file)
                 return log_oom();
 
-        *ret_keyfile = TAKE_PTR(keyfile);
-        *ret_keydev = TAKE_PTR(keydev);
+        *ret_file = TAKE_PTR(file);
+        *ret_device = TAKE_PTR(device);
 
         return 0;
 }
 
-static int generate_keydev_mount(
+static int generate_device_mount(
                 const char *name,
-                const char *keydev,
-                const char *keydev_timeout,
+                const char *device,
+                const char *type_prefix, /* "keydev" or "headerdev" */
+                const char *device_timeout,
                 bool canfail,
+                bool readonly,
                 char **unit,
                 char **mount) {
 
@@ -113,7 +117,7 @@ static int generate_keydev_mount(
         usec_t timeout_us;
 
         assert(name);
-        assert(keydev);
+        assert(device);
         assert(unit);
         assert(mount);
 
@@ -129,7 +133,7 @@ static int generate_keydev_mount(
         if (!name_escaped)
                 return -ENOMEM;
 
-        where = strjoin(arg_runtime_directory, "/keydev-", name_escaped);
+        where = strjoin(arg_runtime_directory, "/", type_prefix, "-", name_escaped);
         if (!where)
                 return -ENOMEM;
 
@@ -151,23 +155,23 @@ static int generate_keydev_mount(
                 "[Mount]\n"
                 "What=%s\n"
                 "Where=%s\n"
-                "Options=ro%s\n", keydev, where, canfail ? ",nofail" : "");
+                "Options=%s%s\n", device, where, readonly ? "ro" : "rw", canfail ? ",nofail" : "");
 
-        if (keydev_timeout) {
-                r = parse_sec_fix_0(keydev_timeout, &timeout_us);
+        if (device_timeout) {
+                r = parse_sec_fix_0(device_timeout, &timeout_us);
                 if (r >= 0) {
-                        r = unit_name_from_path(keydev, ".device", &device_unit);
+                        r = unit_name_from_path(device, ".device", &device_unit);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to generate unit name: %m");
 
                         r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
                                 "# Automatically generated by systemd-cryptsetup-generator \n\n"
-                                "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout);
+                                "[Unit]\nJobRunningTimeoutSec=%s", device_timeout);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to write device drop-in: %m");
 
                 } else
-                        log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout);
+                        log_warning_errno(r, "Failed to parse %s, ignoring: %m", device_timeout);
 
         }
 
@@ -181,8 +185,9 @@ static int generate_keydev_mount(
         return 0;
 }
 
-static int generate_keydev_umount(const char *name,
-                                  const char *keydev_mount,
+static int generate_device_umount(const char *name,
+                                  const char *device_mount,
+                                  const char *type_prefix, /* "keydev" or "headerdev" */
                                   char **ret_umount_unit) {
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *u = NULL, *name_escaped = NULL, *mount = NULL;
@@ -195,11 +200,11 @@ static int generate_keydev_umount(const char *name,
         if (!name_escaped)
                 return -ENOMEM;
 
-        u = strjoin("keydev-", name_escaped, "-umount.service");
+        u = strjoin(type_prefix, "-", name_escaped, "-umount.service");
         if (!u)
                 return -ENOMEM;
 
-        r = unit_name_from_path(keydev_mount, ".mount", &mount);
+        r = unit_name_from_path(device_mount, ".mount", &mount);
         if (r < 0)
                 return r;
 
@@ -212,7 +217,7 @@ static int generate_keydev_umount(const char *name,
                 "DefaultDependencies=no\n"
                 "After=%s\n\n"
                 "[Service]\n"
-                "ExecStart=-" UMOUNT_PATH " %s\n\n", mount, keydev_mount);
+                "ExecStart=-" UMOUNT_PATH " %s\n\n", mount, device_mount);
 
         r = fflush_and_check(f);
         if (r < 0)
@@ -274,13 +279,14 @@ static int create_disk(
                 const char *device,
                 const char *password,
                 const char *keydev,
+                const char *headerdev,
                 const char *options,
                 const char *source) {
 
         _cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
                 *keydev_mount = NULL, *keyfile_timeout_value = NULL,
                 *filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL,
-                *tmp_fstype = NULL;
+                *tmp_fstype = NULL, *filtered_header = NULL, *headerdev_mount = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *dmname;
         bool noauto, nofail, swap, netdev, attach_in_initrd;
@@ -299,7 +305,12 @@ static int create_disk(
         if (keyfile_can_timeout < 0)
                 return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
 
-        detached_header = fstab_filter_options(options, "header\0", NULL, &header_path, NULL);
+        detached_header = fstab_filter_options(
+                options,
+                "header\0",
+                NULL,
+                &header_path,
+                headerdev ? &filtered_header : NULL);
         if (detached_header < 0)
                 return log_error_errno(detached_header, "Failed to parse header= option value: %m");
 
@@ -358,11 +369,19 @@ static int create_disk(
         if (keydev) {
                 _cleanup_free_ char *unit = NULL, *umount_unit = NULL;
 
-                r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
+                r = generate_device_mount(
+                        name,
+                        keydev,
+                        "keydev",
+                        keyfile_timeout_value,
+                        /* canfail = */ keyfile_can_timeout > 0,
+                        /* readonly= */ true,
+                        &unit,
+                        &keydev_mount);
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate keydev mount unit: %m");
 
-                r = generate_keydev_umount(name, keydev_mount, &umount_unit);
+                r = generate_device_umount(name, keydev_mount, "keydev", &umount_unit);
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate keydev umount unit: %m");
 
@@ -378,6 +397,54 @@ static int create_disk(
                 else
                         fprintf(f, "Requires=%s\n", unit);
 
+                if (umount_unit)
+                        fprintf(f,
+                                "Wants=%s\n"
+                                "Before=%s\n",
+                                umount_unit,
+                                umount_unit
+                        );
+        }
+
+        if (headerdev) {
+                _cleanup_free_ char *unit = NULL, *umount_unit = NULL, *p = NULL;
+
+                r = generate_device_mount(
+                        name,
+                        headerdev,
+                        "headerdev",
+                        NULL,
+                        /* canfail=  */ false, /* header is always necessary */
+                        /* readonly= */ false, /* LUKS2 recovery requires rw header access */
+                        &unit,
+                        &headerdev_mount);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate header device mount unit: %m");
+
+                r = generate_device_umount(name, headerdev_mount, "headerdev", &umount_unit);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate header device umount unit: %m");
+
+                p = path_join(headerdev_mount, header_path);
+                if (!p)
+                        return log_oom();
+
+                free_and_replace(header_path, p);
+
+                if (isempty(filtered_header))
+                        p = strjoin("header=", header_path);
+                else
+                        p = strjoin(filtered_header, ",header=", header_path);
+
+                if (!p)
+                        return log_oom();
+
+                free_and_replace(filtered_header, p);
+                options = filtered_header;
+
+                fprintf(f, "After=%s\n"
+                           "Requires=%s\n", unit, unit);
+
                 if (umount_unit) {
                         fprintf(f,
                                 "Wants=%s\n"
@@ -388,10 +455,16 @@ static int create_disk(
                 }
         }
 
+        const char *target;
+        if (in_initrd())
+                target = "initrd-cryptsetup.target";
+        else if (netdev)
+                target = "remote-cryptsetup.target";
+        else
+                target = "cryptsetup.target";
+
         if (!nofail)
-                fprintf(f,
-                        "Before=%s\n",
-                        netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
+                fprintf(f, "Before=%s\n", target);
 
         if (password && !keydev) {
                 r = print_dependencies(f, password);
@@ -400,7 +473,7 @@ static int create_disk(
         }
 
         /* Check if a header option was specified */
-        if (detached_header > 0) {
+        if (detached_header > 0 && !headerdev) {
                 r = print_dependencies(f, header_path);
                 if (r < 0)
                         return r;
@@ -454,8 +527,7 @@ static int create_disk(
                 return log_error_errno(r, "Failed to write unit file %s: %m", n);
 
         if (!noauto) {
-                r = generator_add_symlink(arg_dest,
-                                          netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
+                r = generator_add_symlink(arg_dest, target,
                                           nofail ? "wants" : "requires", n);
                 if (r < 0)
                         return r;
@@ -515,6 +587,52 @@ static crypto_device *get_crypto_device(const char *uuid) {
         return d;
 }
 
+static bool warn_uuid_invalid(const char *uuid, const char *key) {
+        assert(key);
+
+        if (!id128_is_valid(uuid)) {
+                log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key);
+                return true;
+        }
+
+        return false;
+}
+
+static int filter_header_device(const char *options,
+                                char **ret_headerdev,
+                                char **ret_filtered_headerdev_options) {
+        int r;
+        _cleanup_free_ char *headerfile = NULL, *headerdev = NULL, *headerspec = NULL,
+                            *filtered_headerdev = NULL, *filtered_headerspec = NULL;
+
+        assert(ret_headerdev);
+        assert(ret_filtered_headerdev_options);
+
+        r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse header= option value: %m");
+
+        if (r > 0) {
+                r = split_locationspec(headerspec, &headerfile, &headerdev);
+                if (r < 0)
+                        return r;
+
+                if (isempty(filtered_headerspec))
+                        filtered_headerdev = strjoin("header=", headerfile);
+                else
+                        filtered_headerdev = strjoin(filtered_headerspec, ",header=", headerfile);
+
+                if (!filtered_headerdev)
+                        return log_oom();
+        } else
+                filtered_headerdev = TAKE_PTR(filtered_headerspec);
+
+        *ret_filtered_headerdev_options = TAKE_PTR(filtered_headerdev);
+        *ret_headerdev = TAKE_PTR(headerdev);
+
+        return 0;
+}
+
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
         _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
         crypto_device *d;
@@ -548,20 +666,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 d->create = arg_allow_list = true;
 
         } else if (streq(key, "luks.options")) {
+                _cleanup_free_ char *headerdev = NULL, *filtered_headerdev_options = NULL;
 
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
-                if (r == 2) {
-                        d = get_crypto_device(uuid);
-                        if (!d)
-                                return log_oom();
+                if (r != 2)
+                        return free_and_strdup(&arg_default_options, value) < 0 ? log_oom() : 0;
 
-                        free_and_replace(d->options, uuid_value);
-                } else if (free_and_strdup(&arg_default_options, value) < 0)
+                if (warn_uuid_invalid(uuid, key))
+                        return 0;
+
+                d = get_crypto_device(uuid);
+                if (!d)
                         return log_oom();
 
+                r = filter_header_device(uuid_value, &headerdev, &filtered_headerdev_options);
+                if (r < 0)
+                        return r;
+
+                free_and_replace(d->options, filtered_headerdev_options);
+                free_and_replace(d->headerdev, headerdev);
         } else if (streq(key, "luks.key")) {
                 size_t n;
                 _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
@@ -570,7 +696,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
-                n = strspn(value, LETTERS DIGITS "-");
+                n = strspn(value, ALPHANUMERICAL "-");
                 if (value[n] != '=') {
                         if (free_and_strdup(&arg_default_keyfile, value) < 0)
                                  return log_oom();
@@ -581,23 +707,49 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (!uuid)
                         return log_oom();
 
-                if (!id128_is_valid(uuid)) {
-                        log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring.");
+                if (warn_uuid_invalid(uuid, key))
                         return 0;
-                }
 
                 d = get_crypto_device(uuid);
                 if (!d)
                         return log_oom();
 
                 keyspec = value + n + 1;
-                r = split_keyspec(keyspec, &keyfile, &keydev);
+                r = split_locationspec(keyspec, &keyfile, &keydev);
                 if (r < 0)
                         return r;
 
                 free_and_replace(d->keyfile, keyfile);
                 free_and_replace(d->keydev, keydev);
+        } else if (streq(key, "luks.data")) {
+                size_t n;
+                _cleanup_free_ char *datadev = NULL;
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                n = strspn(value, ALPHANUMERICAL "-");
+                if (value[n] != '=') {
+                        log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring.");
+                        return 0;
+                }
+
+                uuid = strndup(value, n);
+                if (!uuid)
+                        return log_oom();
+
+                if (warn_uuid_invalid(uuid, key))
+                        return 0;
+
+                d = get_crypto_device(uuid);
+                if (!d)
+                        return log_oom();
+
+                datadev = fstab_node_to_udev_node(value + n + 1);
+                if (!datadev)
+                        return log_oom();
 
+                free_and_replace(d->datadev, datadev);
         } else if (streq(key, "luks.name")) {
 
                 if (proc_cmdline_value_missing(key, value))
@@ -622,7 +774,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 static int add_crypttab_devices(void) {
         _cleanup_fclose_ FILE *f = NULL;
         unsigned crypttab_line = 0;
-        struct stat st;
         int r;
 
         if (!arg_read_crypttab)
@@ -635,13 +786,9 @@ static int add_crypttab_devices(void) {
                 return 0;
         }
 
-        if (fstat(fileno(f), &st) < 0) {
-                log_error_errno(errno, "Failed to stat %s: %m", arg_crypttab);
-                return 0;
-        }
-
         for (;;) {
-                _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, *keyfile = NULL, *keydev = NULL;
+                _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL,
+                                    *keyfile = NULL, *keydev = NULL, *headerdev = NULL, *filtered_header = NULL;
                 crypto_device *d = NULL;
                 char *l, *uuid;
                 int k;
@@ -677,11 +824,24 @@ static int add_crypttab_devices(void) {
                         continue;
                 }
 
-                r = split_keyspec(keyspec, &keyfile, &keydev);
+                r = split_locationspec(keyspec, &keyfile, &keydev);
                 if (r < 0)
                         return r;
 
-                r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options, arg_crypttab);
+                if (options && (!d || !d->options)) {
+                        r = filter_header_device(options, &headerdev, &filtered_header);
+                        if (r < 0)
+                                return r;
+                        free_and_replace(options, filtered_header);
+                }
+
+                r = create_disk(name,
+                                device,
+                                keyfile,
+                                keydev,
+                                (d && d->options) ? d->headerdev : headerdev,
+                                (d && d->options) ? d->options : options,
+                                arg_crypttab);
                 if (r < 0)
                         return r;
 
@@ -713,9 +873,10 @@ static int add_proc_cmdline_devices(void) {
                         return log_oom();
 
                 r = create_disk(d->name,
-                                device,
+                                d->datadev ?: device,
                                 d->keyfile ?: arg_default_keyfile,
                                 d->keydev,
+                                d->headerdev,
                                 d->options ?: arg_default_options,
                                 "/proc/cmdline");
                 if (r < 0)
index 7d0571f14757c7edefdd0cf21a70f2ec82ce0b34..fb08b4a1a0bbdecb2aceee630dadaac4b4952ec9 100644 (file)
@@ -294,9 +294,9 @@ static int parse_options(const char *options) {
                 _cleanup_free_ char *word = NULL;
                 int r;
 
-                r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
+                r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to parse options: %m");
+                        return log_error_errno(r, "Failed to parse options: %m");
                 if (r == 0)
                         break;
 
@@ -832,10 +832,9 @@ static int run(int argc, char *argv[]) {
         if (argc <= 1)
                 return help();
 
-        if (argc < 3) {
-                log_error("This program requires at least two arguments.");
-                return -EINVAL;
-        }
+        if (argc < 3)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "This program requires at least two arguments.");
 
         log_setup_service();
 
@@ -874,6 +873,9 @@ static int run(int argc, char *argv[]) {
                                 return r;
                 }
 
+                log_debug("%s %s ← %s type=%s cipher=%s", __func__,
+                          argv[2], argv[3], strempty(arg_type), strempty(arg_cipher));
+
                 /* A delicious drop of snake oil */
                 (void) mlockall(MCL_FUTURE);
 
index 80f7107b9d9758aaac1445de1487b68ffd6a924b..472ba6d54985e08e64363dbe80384e215182d08c 100644 (file)
@@ -258,10 +258,9 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
-        if (argc > 2) {
-                log_error("This program expects one or no arguments.");
-                return -EINVAL;
-        }
+        if (argc > 2)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "This program expects one or no arguments.");
 
         umask(0022);
 
@@ -284,10 +283,10 @@ static int run(int argc, char *argv[]) {
                 if (stat(device, &st) < 0)
                         return log_error_errno(errno, "Failed to stat %s: %m", device);
 
-                if (!S_ISBLK(st.st_mode)) {
-                        log_error("%s is not a block device.", device);
-                        return -EINVAL;
-                }
+                if (!S_ISBLK(st.st_mode))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "%s is not a block device.",
+                                               device);
 
                 r = sd_device_new_from_devnum(&dev, 'b', st.st_rdev);
                 if (r < 0)
index eb9098fda95ec79f8902c562a4379edc12783dad..0019f59f0f676ce6a5bac70ec0bcd2837a4d82b1 100644 (file)
@@ -401,7 +401,8 @@ int identity_add_fido2_parameters(
 
         return 0;
 #else
-        return log_error_errno(EOPNOTSUPP, "FIDO2 tokens not supported on this build.");
+        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                               "FIDO2 tokens not supported on this build.");
 #endif
 }
 
@@ -467,7 +468,8 @@ finish:
         fido_dev_info_free(&di, allocated);
         return r;
 #else
-        return log_error_errno(EOPNOTSUPP, "FIDO2 tokens not supported on this build.");
+        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                               "FIDO2 tokens not supported on this build.");
 #endif
 }
 
index 0583171f042ea511afe55b1794ea897a6821edf2..592a6413e1d319e737b08df6d2393bbcf8851efe 100644 (file)
@@ -77,7 +77,9 @@ static int acquire_pkcs11_certificate(
 
         r = pkcs11_find_token(uri, pkcs11_callback, &data);
         if (r == -EAGAIN) /* pkcs11_find_token() doesn't log about this error, but all others */
-                return log_error_errno(ENXIO, "Specified PKCS#11 token with URI '%s' not found.", uri);
+                return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
+                                       "Specified PKCS#11 token with URI '%s' not found.",
+                                       uri);
         if (r < 0)
                 return r;
 
@@ -86,7 +88,8 @@ static int acquire_pkcs11_certificate(
 
         return 0;
 #else
-        return log_error_errno(EOPNOTSUPP, "PKCS#11 tokens not supported on this build.");
+        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                               "PKCS#11 tokens not supported on this build.");
 #endif
 }
 
@@ -415,7 +418,8 @@ int list_pkcs11_tokens(void) {
 
         return 0;
 #else
-        return log_error_errno(EOPNOTSUPP, "PKCS#11 tokens not supported on this build.");
+        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                               "PKCS#11 tokens not supported on this build.");
 #endif
 }
 
index 35c98c9d6dd6a8e913af5d1e241488a71718839a..486aec066d65fab2550c2f5444a328218fee624b 100644 (file)
@@ -99,7 +99,7 @@ static int acquire_bus(sd_bus **bus) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to bus: %m");
+                return bus_log_connect_error(r);
 
         (void) sd_bus_set_allow_interactive_authorization(*bus, arg_ask_password);
 
@@ -1844,7 +1844,28 @@ static int lock_all_homes(int argc, char *argv[], void *userdata) {
 
         r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to lock home: %s", bus_error_message(&error, r));
+                return log_error_errno(r, "Failed to lock all homes: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+static int deactivate_all_homes(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        r = acquire_bus(&bus);
+        if (r < 0)
+                return r;
+
+        r = bus_message_new_method_call(bus, &m, bus_mgr, "DeactivateAllHomes");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to deactivate all homes: %s", bus_error_message(&error, r));
 
         return 0;
 }
@@ -1902,6 +1923,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  lock USER…                  Temporarily lock an active home area\n"
                "  unlock USER…                Unlock a temporarily locked home area\n"
                "  lock-all                    Lock all suitable home areas\n"
+               "  deactivate-all              Deactivate all active home areas\n"
                "  with USER [COMMAND…]        Run shell or command with access to a home area\n"
                "\n%4$sOptions:%5$s\n"
                "  -h --help                   Show this help\n"
@@ -3328,21 +3350,22 @@ static int redirect_bus_mgr(void) {
 
 static int run(int argc, char *argv[]) {
         static const Verb verbs[] = {
-                { "help",         VERB_ANY, VERB_ANY, 0,            help                },
-                { "list",         VERB_ANY, 1,        VERB_DEFAULT, list_homes          },
-                { "activate",     2,        VERB_ANY, 0,            activate_home       },
-                { "deactivate",   2,        VERB_ANY, 0,            deactivate_home     },
-                { "inspect",      VERB_ANY, VERB_ANY, 0,            inspect_home        },
-                { "authenticate", VERB_ANY, VERB_ANY, 0,            authenticate_home   },
-                { "create",       VERB_ANY, 2,        0,            create_home         },
-                { "remove",       2,        VERB_ANY, 0,            remove_home         },
-                { "update",       VERB_ANY, 2,        0,            update_home         },
-                { "passwd",       VERB_ANY, 2,        0,            passwd_home         },
-                { "resize",       2,        3,        0,            resize_home         },
-                { "lock",         2,        VERB_ANY, 0,            lock_home           },
-                { "unlock",       2,        VERB_ANY, 0,            unlock_home         },
-                { "with",         2,        VERB_ANY, 0,            with_home           },
-                { "lock-all",     VERB_ANY, 1,        0,            lock_all_homes      },
+                { "help",           VERB_ANY, VERB_ANY, 0,            help                 },
+                { "list",           VERB_ANY, 1,        VERB_DEFAULT, list_homes           },
+                { "activate",       2,        VERB_ANY, 0,            activate_home        },
+                { "deactivate",     2,        VERB_ANY, 0,            deactivate_home      },
+                { "inspect",        VERB_ANY, VERB_ANY, 0,            inspect_home         },
+                { "authenticate",   VERB_ANY, VERB_ANY, 0,            authenticate_home    },
+                { "create",         VERB_ANY, 2,        0,            create_home          },
+                { "remove",         2,        VERB_ANY, 0,            remove_home          },
+                { "update",         VERB_ANY, 2,        0,            update_home          },
+                { "passwd",         VERB_ANY, 2,        0,            passwd_home          },
+                { "resize",         2,        3,        0,            resize_home          },
+                { "lock",           2,        VERB_ANY, 0,            lock_home            },
+                { "unlock",         2,        VERB_ANY, 0,            unlock_home          },
+                { "with",           2,        VERB_ANY, 0,            with_home            },
+                { "lock-all",       VERB_ANY, 1,        0,            lock_all_homes       },
+                { "deactivate-all", VERB_ANY, 1,        0,            deactivate_all_homes },
                 {}
         };
 
index 328ec32fd368485fe4a66509b6ca2bb6a16485be..6d0f0fbd0e52b53d41365129851a3040c803ef00 100644 (file)
@@ -2482,6 +2482,50 @@ static int home_dispatch_lock_all(Home *h, Operation *o) {
         return 1;
 }
 
+static int home_dispatch_deactivate_all(Home *h, Operation *o) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(h);
+        assert(o);
+        assert(o->type == OPERATION_DEACTIVATE_ALL);
+
+        switch (home_get_state(h)) {
+
+        case HOME_UNFIXATED:
+        case HOME_ABSENT:
+        case HOME_INACTIVE:
+        case HOME_DIRTY:
+                log_info("Home %s is already deactivated.", h->user_name);
+                r = 1; /* done */
+                break;
+
+        case HOME_LOCKED:
+                log_info("Home %s is currently locked, not deactivating.", h->user_name);
+                r = 1; /* done */
+                break;
+
+        case HOME_ACTIVE:
+                log_info("Deactivating home %s.", h->user_name);
+                r = home_deactivate_internal(h, false, &error);
+                break;
+
+        default:
+                /* All other cases means we are currently executing an operation, which means the job remains
+                 * pending. */
+                return 0;
+        }
+
+        assert(!h->current_operation);
+
+        if (r != 0) /* failure or completed */
+                operation_result(o, r, &error);
+        else /* ongoing */
+                h->current_operation = operation_ref(o);
+
+        return 1;
+}
+
 static int home_dispatch_pipe_eof(Home *h, Operation *o) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
@@ -2579,6 +2623,7 @@ static int on_pending(sd_event_source *s, void *userdata) {
                         [OPERATION_ACQUIRE]          = home_dispatch_acquire,
                         [OPERATION_RELEASE]          = home_dispatch_release,
                         [OPERATION_LOCK_ALL]         = home_dispatch_lock_all,
+                        [OPERATION_DEACTIVATE_ALL]   = home_dispatch_deactivate_all,
                         [OPERATION_PIPE_EOF]         = home_dispatch_pipe_eof,
                         [OPERATION_DEACTIVATE_FORCE] = home_dispatch_deactivate_force,
                 };
index fa3acb5244a140667e340e39847efb1a94c03e3c..a599c582976c72e3b79011f24ffff5edd9c2c893 100644 (file)
@@ -591,7 +591,45 @@ static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus
         }
 
         if (waiting) /* At least one lock operation was enqeued, let's leave here without a reply: it will
-                        * be sent as soon as the last of the lock operations completed. */
+                      * be sent as soon as the last of the lock operations completed. */
+                return 1;
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_deactivate_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_(operation_unrefp) Operation *o = NULL;
+        bool waiting = false;
+        Manager *m = userdata;
+        Home *h;
+        int r;
+
+        assert(m);
+
+        /* This is called from systemd-homed-activate.service's ExecStop= command to ensure that all home
+         * directories are shutdown before the system goes down. Note that we don't do this from
+         * systemd-homed.service itself since we want to allow restarting of it without tearing down all home
+         * directories. */
+
+        HASHMAP_FOREACH(h, m->homes_by_name) {
+
+                if (!o) {
+                        o = operation_new(OPERATION_DEACTIVATE_ALL, message);
+                        if (!o)
+                                return -ENOMEM;
+                }
+
+                log_info("Automatically deactivating home of user %s.", h->user_name);
+
+                r = home_schedule_operation(h, o, error);
+                if (r < 0)
+                        return r;
+
+                waiting = true;
+        }
+
+        if (waiting) /* At least one lock operation was enqeued, let's leave here without a reply: it will be
+                      * sent as soon as the last of the deactivation operations completed. */
                 return 1;
 
         return sd_bus_reply_method_return(message, NULL);
@@ -804,6 +842,7 @@ static const sd_bus_vtable manager_vtable[] = {
 
         /* An operation that acts on all homes that allow it */
         SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
+        SD_BUS_METHOD("DeactivateAllHomes", NULL, NULL, method_deactivate_all_homes, 0),
 
         SD_BUS_VTABLE_END
 };
index 224de9185253eb81793450ff497ace920a4858c6..0771dc6be0e51e48cba01f2c065c482fa4f09381 100644 (file)
@@ -9,6 +9,7 @@ typedef enum OperationType {
         OPERATION_ACQUIRE,           /* enqueued on AcquireHome() */
         OPERATION_RELEASE,           /* enqueued on ReleaseHome() */
         OPERATION_LOCK_ALL,          /* enqueued on LockAllHomes() */
+        OPERATION_DEACTIVATE_ALL,    /* enqueued on DeactivateAllHomes() */
         OPERATION_PIPE_EOF,          /* enqueued when we see EOF on the per-home reference pipes */
         OPERATION_DEACTIVATE_FORCE,  /* enqueued on hard $HOME unplug */
         OPERATION_IMMEDIATE,         /* this is never enqueued, it's just a marker we immediately started executing an operation without enqueuing anything first. */
index 14e2002c7325fab5e7177d046a901e08b2383869..4b924b2a7c0117afe93d0a195e76850fa40558f3 100644 (file)
@@ -910,7 +910,8 @@ static int user_record_compile_effective_passwords(
          * the old literal password only (and do not care for the old PKCS#11 token) */
 
         if (strv_isempty(h->hashed_password))
-                return log_error_errno(EINVAL, "User record has no hashed passwords, refusing.");
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "User record has no hashed passwords, refusing.");
 
         /* Generates the list of plaintext passwords to propagate to LUKS/fscrypt devices, and checks whether
          * we have a plaintext password for each hashed one. If we are missing one we'll fail, since we
index 8fe52f44aac607cb8c6683e04fbeaaded485629e..4d7c99733e6b8822f30b6c0403fb3d7b680cf4ce 100644 (file)
@@ -142,7 +142,7 @@ static int acquire_user_record(
         if (r == PAM_SUCCESS && json) {
                 /* We determined earlier that this is not a homed user? Then exit early. (We use -1 as
                  * negative cache indicator) */
-                if (json == (void*) -1)
+                if (json == POINTER_MAX)
                         return PAM_USER_UNKNOWN;
         } else {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -235,7 +235,7 @@ static int acquire_user_record(
 
 user_unknown:
         /* Cache this, so that we don't check again */
-        r = pam_set_data(handle, homed_field, (void*) -1, NULL);
+        r = pam_set_data(handle, homed_field, POINTER_MAX, NULL);
         if (r != PAM_SUCCESS)
                 pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s' to invalid, ignoring: %s",
                            homed_field, pam_strerror(handle, r));
@@ -833,8 +833,6 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
                 pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed account management");
 
         r = acquire_home(handle, /* please_authenticate = */ false, please_suspend, debug);
-        if (r == PAM_USER_UNKNOWN)
-                return PAM_SUCCESS; /* we don't have anything to say about users we don't manage */
         if (r != PAM_SUCCESS)
                 return r;
 
index c6d8b8d08204891e8aff7576c3016182fbff2291..c38600b9c3f2c8e72afc23292861dc00229922a5 100644 (file)
@@ -194,10 +194,9 @@ static int show_status(int argc, char **argv, void *userdata) {
         if (arg_pretty || arg_static || arg_transient) {
                 const char *attr;
 
-                if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
-                        log_error("Cannot query more than one name type at a time");
-                        return -EINVAL;
-                }
+                if (!!arg_static + !!arg_pretty + !!arg_transient > 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Cannot query more than one name type at a time");
 
                 attr = arg_pretty ? "PrettyHostname" :
                         arg_static ? "StaticHostname" : "Hostname";
index db55fa50d5d9f2cc8dffb75922c5b68b5ddecfb5..f631f857fc9ccbe932f7e8695a41b77172dcea60 100644 (file)
@@ -126,10 +126,10 @@ static int import_fs(int argc, char *argv[], void *userdata) {
         local = empty_or_dash_to_null(local);
 
         if (local) {
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local image name '%s' is not valid.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local image name '%s' is not valid.",
+                                               local);
 
                 if (!arg_force) {
                         r = image_find(IMAGE_MACHINE, local, NULL);
@@ -137,8 +137,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
                                 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;
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "Image '%s' already exists.",
+                                                       local);
                         }
                 }
         } else
index cc2855745962af444b4c0c30150c1b1e47b39cb3..64ec066a8f326e74921b4103d186075b53189bc3 100644 (file)
@@ -64,10 +64,10 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local image name '%s' is not valid.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local image name '%s' is not valid.",
+                                               local);
 
                 if (!arg_force) {
                         r = image_find(IMAGE_MACHINE, local, NULL);
@@ -75,8 +75,9 @@ static int import_tar(int argc, char *argv[], void *userdata) {
                                 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;
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "Image '%s' already exists.",
+                                                       local);
                         }
                 }
         } else
@@ -158,10 +159,10 @@ static int import_raw(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local image name '%s' is not valid.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local image name '%s' is not valid.",
+                                               local);
 
                 if (!arg_force) {
                         r = image_find(IMAGE_MACHINE, local, NULL);
@@ -169,8 +170,9 @@ static int import_raw(int argc, char *argv[], void *userdata) {
                                 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;
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "Image '%s' already exists.",
+                                                       local);
                         }
                 }
         } else
index 249ea533e63b63c474aef241c471df999be444e0..fdc70447e1286854b6d9d1473f52afc747d09e42 100644 (file)
@@ -389,10 +389,9 @@ int pull_verify(PullJob *main_job,
 
         assert(checksum_job->state == PULL_JOB_DONE);
 
-        if (!checksum_job->payload || checksum_job->payload_size <= 0) {
-                log_error("Checksum is empty, cannot verify.");
-                return -EBADMSG;
-        }
+        if (!checksum_job->payload || checksum_job->payload_size <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                       "Checksum is empty, cannot verify.");
 
         r = verify_one(checksum_job, main_job);
         if (r < 0)
@@ -414,10 +413,9 @@ int pull_verify(PullJob *main_job,
 
         assert(signature_job->state == PULL_JOB_DONE);
 
-        if (!signature_job->payload || signature_job->payload_size <= 0) {
-                log_error("Signature is empty, cannot verify.");
-                return -EBADMSG;
-        }
+        if (!signature_job->payload || signature_job->payload_size <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                       "Signature is empty, cannot verify.");
 
         r = pipe2(gpg_pipe, O_CLOEXEC);
         if (r < 0)
index 7e8712493fb5412592695a0e2f4bd412172e66be..9b27ec26306e7fbd19cf99580cc8d61f8158e855 100644 (file)
@@ -49,10 +49,9 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
         int r;
 
         url = argv[1];
-        if (!http_url_is_valid(url)) {
-                log_error("URL '%s' is not valid.", url);
-                return -EINVAL;
-        }
+        if (!http_url_is_valid(url))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "URL '%s' is not valid.", url);
 
         if (argc >= 3)
                 local = argv[2];
@@ -73,10 +72,10 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local image name '%s' is not valid.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local image name '%s' is not valid.",
+                                               local);
 
                 if (!arg_force) {
                         r = image_find(IMAGE_MACHINE, local, NULL);
@@ -84,8 +83,9 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
                                 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;
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "Image '%s' already exists.",
+                                                       local);
                         }
                 }
 
@@ -135,10 +135,9 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
         int r;
 
         url = argv[1];
-        if (!http_url_is_valid(url)) {
-                log_error("URL '%s' is not valid.", url);
-                return -EINVAL;
-        }
+        if (!http_url_is_valid(url))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "URL '%s' is not valid.", url);
 
         if (argc >= 3)
                 local = argv[2];
@@ -159,10 +158,10 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local image name '%s' is not valid.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local image name '%s' is not valid.",
+                                               local);
 
                 if (!arg_force) {
                         r = image_find(IMAGE_MACHINE, local, NULL);
@@ -170,8 +169,9 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
                                 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;
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "Image '%s' already exists.",
+                                                       local);
                         }
                 }
 
index 852f9e07bab3078d555eca373bbfe6c87463a0f9..a1bd4a379ede1661d79082fd3aa934279d20c7f8 100644 (file)
@@ -544,10 +544,10 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
         assert(fdt >= 0);
 
         ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
-        if (ret != LZMA_OK) {
-                log_error("Failed to initialize XZ encoder: code %u", ret);
-                return -EINVAL;
-        }
+        if (ret != LZMA_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Failed to initialize XZ encoder: code %u",
+                                       ret);
 
         for (;;) {
                 if (s.avail_in == 0 && action == LZMA_RUN) {
@@ -579,10 +579,10 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
                 }
 
                 ret = lzma_code(&s, action);
-                if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END)) {
-                        log_error("Compression failed: code %u", ret);
-                        return -EBADMSG;
-                }
+                if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
+                        return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                               "Compression failed: code %u",
+                                               ret);
 
                 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
                         ssize_t n, k;
@@ -664,10 +664,10 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
                 offset += n;
                 total_out += n;
 
-                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
-                        log_debug("Compressed stream longer than %"PRIu64" bytes", max_bytes);
-                        return -EFBIG;
-                }
+                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EFBIG),
+                                               "Compressed stream longer than %" PRIu64 " bytes",
+                                               max_bytes);
 
                 if (size - offset < frame_size + 4) {
                         k = loop_write(fdt, buf, offset, false);
@@ -715,10 +715,10 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
         assert(fdt >= 0);
 
         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
-        if (ret != LZMA_OK) {
-                log_debug("Failed to initialize XZ decoder: code %u", ret);
-                return -ENOMEM;
-        }
+        if (ret != LZMA_OK)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOMEM),
+                                       "Failed to initialize XZ decoder: code %u",
+                                       ret);
 
         for (;;) {
                 if (s.avail_in == 0 && action == LZMA_RUN) {
@@ -741,10 +741,10 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
                 }
 
                 ret = lzma_code(&s, action);
-                if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END)) {
-                        log_debug("Decompression failed: code %u", ret);
-                        return -EBADMSG;
-                }
+                if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                               "Decompression failed: code %u",
+                                               ret);
 
                 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
                         ssize_t n, k;
@@ -772,8 +772,8 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
                 }
         }
 #else
-        log_debug("Cannot decompress file. Compiled without XZ support.");
-        return -EPROTONOSUPPORT;
+        return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
+                               "Cannot decompress file. Compiled without XZ support.");
 #endif
 }
 
@@ -833,8 +833,8 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
         munmap(src, st.st_size);
         return r;
 #else
-        log_debug("Cannot decompress file. Compiled without LZ4 support.");
-        return -EPROTONOSUPPORT;
+        return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
+                               "Cannot decompress file. Compiled without LZ4 support.");
 #endif
 }
 
@@ -1043,8 +1043,8 @@ int decompress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
                 (double) (max_bytes - left) / in_bytes * 100);
         return 0;
 #else
-        log_debug("Cannot decompress file. Compiled without ZSTD support.");
-        return -EPROTONOSUPPORT;
+        return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
+                               "Cannot decompress file. Compiled without ZSTD support.");
 #endif
 }
 
index d51d03acd9de09ccecb815b6002b4224e55ed2d3..64882eb4ee4fc67fa8c2c1969223726bd7e1c6ab 100644 (file)
@@ -139,7 +139,7 @@ _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int
 
                 if (i >= n) {
                         n = MAX(i*2, 4);
-                        c = realloc(iov, n * sizeof(struct iovec));
+                        c = reallocarray(iov, n, sizeof(struct iovec));
                         if (!c) {
                                 r = -ENOMEM;
                                 goto fail;
index 52e204ee1155fce11a4ec914511d278d1c5eec5d..e43e9d1afac95000f1d7f590bb0f4b2edf2c120b 100644 (file)
@@ -199,10 +199,9 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) {
         assert(j);
         assert(devpath);
 
-        if (!path_startswith(devpath, "/dev/")) {
-                log_error("Devpath does not start with /dev/");
-                return -EINVAL;
-        }
+        if (!path_startswith(devpath, "/dev/"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Devpath does not start with /dev/");
 
         if (stat(devpath, &st) < 0)
                 return log_error_errno(errno, "Couldn't stat file: %m");
@@ -1055,35 +1054,30 @@ static int parse_argv(int argc, char *argv[]) {
         if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
                 arg_lines = 10;
 
-        if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root + !!arg_image > 1) {
-                log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
-                return -EINVAL;
-        }
+        if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root + !!arg_image > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
 
-        if (arg_since_set && arg_until_set && arg_since > arg_until) {
-                log_error("--since= must be before --until=.");
-                return -EINVAL;
-        }
+        if (arg_since_set && arg_until_set && arg_since > arg_until)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--since= must be before --until=.");
 
-        if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
-                log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
-                return -EINVAL;
-        }
+        if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Please specify only one of --since=, --cursor=, and --after-cursor.");
 
-        if (arg_follow && arg_reverse) {
-                log_error("Please specify either --reverse= or --follow=, not both.");
-                return -EINVAL;
-        }
+        if (arg_follow && arg_reverse)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Please specify either --reverse= or --follow=, not both.");
 
-        if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
-                log_error("Extraneous arguments starting with '%s'", argv[optind]);
-                return -EINVAL;
-        }
+        if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Extraneous arguments starting with '%s'",
+                                       argv[optind]);
 
-        if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) {
-                log_error("Using --boot or --list-boots with --merge is not supported.");
-                return -EINVAL;
-        }
+        if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Using --boot or --list-boots with --merge is not supported.");
 
         if (!strv_isempty(arg_system_units) && arg_journal_type == SD_JOURNAL_CURRENT_USER) {
                 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
@@ -1921,7 +1915,8 @@ static int setup_keys(void) {
                         "Please write down the following %ssecret verification key%s. It should be stored\n"
                         "in a safe location and should not be saved locally on disk.\n"
                         "\n\t%s",
-                        hn ?: "", hn ? "/" : "", SD_ID128_FORMAT_VAL(machine),
+                        strempty(hn), hn ? "/" : "",
+                        SD_ID128_FORMAT_VAL(machine),
                         ansi_highlight(), ansi_normal(),
                         p,
                         format_timespan(tsb, sizeof(tsb), arg_interval, 0),
@@ -2476,7 +2471,7 @@ int main(int argc, char *argv[]) {
                                 after_cursor = true;
                         }
                 } else
-                        after_cursor = !!arg_after_cursor;
+                        after_cursor = arg_after_cursor;
 
                 if (cursor) {
                         r = sd_journal_seek_cursor(j, cursor);
index 34ba24daf64c3f2f265195c2ed7c9d7f5f627f04..ab6aadcb7813fe39d39f415abd2ba2d7b8b75fa8 100644 (file)
@@ -55,6 +55,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "syslog-util.h"
+#include "user-record.h"
 #include "user-util.h"
 
 #define USER_JOURNALS_MAX 1024
index 50aab11c6a8b61182f4a3914477e7b7909aa79bb..924d727d97ce92b90bf5e2642b3d204f4658d451 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "alloc-util.h"
 #include "chattr-util.h"
+#include "io-util.h"
 #include "journal-file.h"
 #include "journal-internal.h"
 #include "log.h"
@@ -92,13 +93,11 @@ static void run_test(void) {
                 previous_ts = ts;
 
                 assert_se(asprintf(&p, "NUMBER=%u", i) >= 0);
-                iovec[0].iov_base = p;
-                iovec[0].iov_len = strlen(p);
+                iovec[0] = IOVEC_MAKE(p, strlen(p));
 
                 assert_se(asprintf(&q, "MAGIC=%s", i % 5 == 0 ? "quux" : "waldo") >= 0);
 
-                iovec[1].iov_base = q;
-                iovec[1].iov_len = strlen(q);
+                iovec[1] = IOVEC_MAKE(q, strlen(q));
 
                 if (i % 10 == 0)
                         assert_se(journal_file_append_entry(three, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
index d0610a32e23d5defcca83889ea716bfb2a4e491e..e7dbec1511cd5f831f65e393218141e2325be398 100644 (file)
@@ -26,11 +26,10 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) {
         if (duid_len > MAX_DUID_LEN)
                 return -EINVAL;
 
-        if (!strict) {
+        if (!strict)
                 /* Strict validation is not requested. We only ensure that the
                  * DUID is not too long. */
                 return 0;
-        }
 
         switch (duid_type) {
         case DUID_TYPE_LLT:
index 265b6eab4436b46768b46f3ac996560e0f3ac9cf..53c43508749a7e472644799e3f4b1c5c079e01ef 100644 (file)
@@ -25,6 +25,8 @@
 #include "io-util.h"
 #include "memory-util.h"
 #include "random-util.h"
+#include "set.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
@@ -75,9 +77,7 @@ struct sd_dhcp_client {
         union sockaddr_union link;
         sd_event_source *receive_message;
         bool request_broadcast;
-        uint8_t *req_opts;
-        size_t req_opts_allocated;
-        size_t req_opts_size;
+        Set *req_opts;
         bool anonymize;
         be32_t last_addr;
         uint8_t mac_addr[MAX_MAC_ADDR_LEN];
@@ -230,8 +230,6 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast)
 }
 
 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
-        size_t i;
-
         assert_return(client, -EINVAL);
         assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
 
@@ -248,17 +246,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
                 break;
         }
 
-        for (i = 0; i < client->req_opts_size; i++)
-                if (client->req_opts[i] == option)
-                        return -EEXIST;
-
-        if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
-                            client->req_opts_size + 1))
-                return -ENOMEM;
-
-        client->req_opts[client->req_opts_size++] = option;
-
-        return 0;
+        return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
 }
 
 int sd_dhcp_client_set_request_address(
@@ -725,6 +713,10 @@ static void client_stop(sd_dhcp_client *client, int error) {
         client_initialize(client);
 }
 
+static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
+        return CMP(*a, *b);
+}
+
 static int client_message_init(
                 sd_dhcp_client *client,
                 DHCPPacket **ret,
@@ -835,10 +827,26 @@ static int client_message_init(
            MAY contain the Parameter Request List option. */
         /* NOTE: in case that there would be an option to do not send
          * any PRL at all, the size should be checked before sending */
-        if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
+        if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) {
+                _cleanup_free_ uint8_t *opts = NULL;
+                size_t n_opts, i = 0;
+                void *val;
+
+                n_opts = set_size(client->req_opts);
+                opts = new(uint8_t, n_opts);
+                if (!opts)
+                        return -ENOMEM;
+
+                SET_FOREACH(val, client->req_opts)
+                        opts[i++] = PTR_TO_UINT8(val);
+                assert(i == n_opts);
+
+                /* For anonymizing the request, let's sort the options. */
+                typesafe_qsort(opts, n_opts, cmp_uint8);
+
                 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
                                        SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
-                                       client->req_opts_size, client->req_opts);
+                                       n_opts, opts);
                 if (r < 0)
                         return r;
         }
@@ -1880,12 +1888,11 @@ static int client_receive_message_udp(
         assert(client);
 
         buflen = next_datagram_size_fd(fd);
-        if (buflen == -ENETDOWN) {
+        if (buflen == -ENETDOWN)
                 /* the link is down. Don't return an error or the I/O event
                    source will be disconnected and we won't be able to receive
                    packets again when the link comes back. */
                 return 0;
-        }
         if (buflen < 0)
                 return buflen;
 
@@ -2128,9 +2135,10 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
 }
 
 int sd_dhcp_client_stop(sd_dhcp_client *client) {
-        DHCP_CLIENT_DONT_DESTROY(client);
+        if (!client)
+                return 0;
 
-        assert_return(client, -EINVAL);
+        DHCP_CLIENT_DONT_DESTROY(client);
 
         client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
         client->state = DHCP_STATE_STOPPED;
@@ -2188,7 +2196,7 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
 
         sd_dhcp_lease_unref(client->lease);
 
-        free(client->req_opts);
+        set_free(client->req_opts);
         free(client->hostname);
         free(client->vendor_class_identifier);
         free(client->mudurl);
@@ -2201,6 +2209,10 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
 
 int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
+        const uint8_t *opts;
+        size_t n_opts;
+        int r;
+
         assert_return(ret, -EINVAL);
 
         _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
@@ -2220,14 +2232,18 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
         };
         /* NOTE: this could be moved to a function. */
         if (anonymize) {
-                client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
-                client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
+                n_opts = ELEMENTSOF(default_req_opts_anonymize);
+                opts = default_req_opts_anonymize;
         } else {
-                client->req_opts_size = ELEMENTSOF(default_req_opts);
-                client->req_opts = memdup(default_req_opts, client->req_opts_size);
+                n_opts = ELEMENTSOF(default_req_opts);
+                opts = default_req_opts;
+        }
+
+        for (size_t i = 0; i < n_opts; i++) {
+                r = sd_dhcp_client_set_request_option(client, opts[i]);
+                if (r < 0)
+                        return r;
         }
-        if (!client->req_opts)
-                return -ENOMEM;
 
         *ret = TAKE_PTR(client);
 
index 0bc5fa321018da09e37dbdee413d9b6471506c77..5f89d00452e640a8625e80c0be13af420fb9d41a 100644 (file)
@@ -779,7 +779,7 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d
                                         return r;
 
                                 n += r;
-                        } else if ((c & 0xc0) == 0xc0) {
+                        } else if (FLAGS_SET(c, 0xc0)) {
                                 /* Pointer */
 
                                 uint8_t d;
@@ -1233,10 +1233,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                 if (!a)
                         return -ENOMEM;
 
-                if (!strv_isempty(a)) {
-                        lease->search_domains = a;
-                        a = NULL;
-                }
+                if (!strv_isempty(a))
+                        lease->search_domains = TAKE_PTR(a);
         }
 
         if (routes) {
index a34a55919e2dd90f4eac7c3c1122b8d739e12009..cab77070170779ab7188cdd225ad1444e3eab5f2 100644 (file)
@@ -225,7 +225,8 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
 }
 
 int sd_dhcp_server_stop(sd_dhcp_server *server) {
-        assert_return(server, -EINVAL);
+        if (!server)
+                return 0;
 
         server->receive_message =
                 sd_event_source_unref(server->receive_message);
@@ -566,7 +567,7 @@ static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
 }
 
 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
-                                  be32_t gateway, uint8_t chaddr[]) {
+                                  be32_t gateway, const uint8_t chaddr[]) {
         _cleanup_free_ DHCPPacket *packet = NULL;
         size_t optoffset = 0;
         int r;
index 6bbc23f131f0093c7a1b86b748f5b44d6b6d1408..6d27c4685eddd030cc03357ab0d2c41ab3e07d6d 100644 (file)
@@ -270,7 +270,7 @@ static int dhcp6_client_set_duid_internal(
         assert_return(duid_len == 0 || duid != NULL, -EINVAL);
         assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
 
-        if (duid != NULL) {
+        if (duid) {
                 r = dhcp_validate_duid_len(duid_type, duid_len, true);
                 if (r < 0) {
                         r = dhcp_validate_duid_len(duid_type, duid_len, false);
@@ -1420,12 +1420,11 @@ static int client_receive_message(
         assert(client->event);
 
         buflen = next_datagram_size_fd(fd);
-        if (buflen == -ENETDOWN) {
+        if (buflen == -ENETDOWN)
                 /* the link is down. Don't return an error or the I/O event
                    source will be disconnected and we won't be able to receive
                    packets again when the link comes back. */
                 return 0;
-        }
         if (buflen < 0)
                 return buflen;
 
@@ -1677,7 +1676,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
 }
 
 int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
-        assert_return(client, -EINVAL);
+        if (!client)
+                return 0;
 
         client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
 
index ecd91cd927cd1f412ccd68c7f888492eaf5d5e59..ff333914e903e8c6db864721d1345face59aeb7a 100644 (file)
@@ -144,7 +144,8 @@ static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
 int sd_ipv4acd_stop(sd_ipv4acd *acd) {
         IPv4ACDState old_state;
 
-        assert_return(acd, -EINVAL);
+        if (!acd)
+                return 0;
 
         old_state = acd->state;
 
index 4f4d9ebe87719add28630b590dcc4057f4d61349..293a4644a23b8fbbddf15a410d729a63aa76108f 100644 (file)
@@ -89,7 +89,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
 }
 
 int sd_ipv4ll_stop(sd_ipv4ll *ll) {
-        assert_return(ll, -EINVAL);
+        if (!ll)
+                return 0;
 
         return sd_ipv4acd_stop(ll->acd);
 }
index b0a11fe20b618822a573b7b690fe5e711eef6f83..e536f90d19478ba14db4091ea09bebbd7ab430d0 100644 (file)
@@ -276,7 +276,8 @@ fail:
 }
 
 _public_ int sd_lldp_stop(sd_lldp *lldp) {
-        assert_return(lldp, -EINVAL);
+        if (!lldp)
+                return 0;
 
         if (lldp->fd < 0)
                 return 0;
index 9922203ac4be88002c91d7e2ca06eb344b925634..92e772d352fc2a64b95620ed9b62d16f73d81d5a 100644 (file)
@@ -321,7 +321,8 @@ static int ndisc_timeout_no_ra(sd_event_source *s, uint64_t usec, void *userdata
 }
 
 _public_ int sd_ndisc_stop(sd_ndisc *nd) {
-        assert_return(nd, -EINVAL);
+        if (!nd)
+                return 0;
 
         if (nd->fd < 0)
                 return 0;
index 016808667cf3ab0fcfb5518ab3ca07fce1b0a466..9656d7c969ce9ca44d0369cdaba2d705900ddd36 100644 (file)
@@ -353,7 +353,8 @@ fail:
 _public_ int sd_radv_stop(sd_radv *ra) {
         int r;
 
-        assert_return(ra, -EINVAL);
+        if (!ra)
+                return 0;
 
         if (ra->state == SD_RADV_STATE_IDLE)
                 return 0;
index 4a0b71be1cf036fc8ef3e52302a4e1cbaccd357a..4d748ea66d0750eddd655b603c59a1b816b0bbda 100644 (file)
@@ -71,40 +71,29 @@ static void test_request_basic(sd_event *e) {
         assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
         assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
 
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_ROUTER) == -EEXIST);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == 0);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_ROUTER) == 0);
         /* This PRL option is not set when using Anonymize, but in this test
          * Anonymize settings are not being used. */
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_HOST_NAME) == -EEXIST);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST);
-
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_PAD) == -EINVAL);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_END) == -EINVAL);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
-                        == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 0);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME) == 0);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == 0);
+
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PAD) == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_END) == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
 
         /* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
          * default PRL when using Anonymize, so it is changed to other option
          * that is not set by default, to check that it was set successfully.
          * Options not set by default (using or not anonymize) are option 17
          * (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
+        assert_se(sd_dhcp_client_set_request_option(client, 17) == 1);
+        assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
+        assert_se(sd_dhcp_client_set_request_option(client, 42) == 1);
         assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
-        assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
-        assert_se(sd_dhcp_client_set_request_option(client, 42) == 0);
-        assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
 
         sd_dhcp_client_unref(client);
 }
@@ -126,19 +115,15 @@ static void test_request_anonymize(sd_event *e) {
         r = sd_dhcp_client_attach_event(client, e, 0);
         assert_se(r >= 0);
 
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_NETBIOS_NAMESERVER) == -EEXIST);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_NETBIOS_NAMESERVER) == 0);
         /* This PRL option is not set when using Anonymize */
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_HOST_NAME) == 0);
-        assert_se(sd_dhcp_client_set_request_option(client,
-                                        SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
-                        == -EINVAL);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 1);
+        assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
 
         /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
          * default PRL when using Anonymize, */
+        assert_se(sd_dhcp_client_set_request_option(client, 101) == 1);
         assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
-        assert_se(sd_dhcp_client_set_request_option(client, 101) == -EEXIST);
 
         sd_dhcp_client_unref(client);
 }
index a45d98f669077d61fe9534ceafc8c9aff03d16a6..16a4f16bfa4a6b961824d40c81a6b289c2551698 100644 (file)
@@ -23,10 +23,10 @@ static void test_pool(struct in_addr *address, unsigned size, int ret) {
 static int test_basic(sd_event *event) {
         _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
         struct in_addr address_lo = {
-                .s_addr = htonl(INADDR_LOOPBACK),
+                .s_addr = htobe32(INADDR_LOOPBACK),
         };
         struct in_addr address_any = {
-                .s_addr = htonl(INADDR_ANY),
+                .s_addr = htobe32(INADDR_ANY),
         };
         int r;
 
@@ -105,7 +105,7 @@ static void test_message_handler(void) {
                 .end = SD_DHCP_OPTION_END,
         };
         struct in_addr address_lo = {
-                .s_addr = htonl(INADDR_LOOPBACK),
+                .s_addr = htobe32(INADDR_LOOPBACK),
         };
 
         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
index c6dfcd679121ac85207a20d4adb13619a4c727fb..6e7f2eee53b209e5c1b58fd9d0695337cfa64deb 100644 (file)
@@ -726,6 +726,8 @@ LIBSYSTEMD_247 {
 global:
         sd_event_add_time_relative;
         sd_event_source_set_time_relative;
+        sd_event_source_get_exit_on_failure;
+        sd_event_source_set_exit_on_failure;
 
         sd_bus_error_has_names_sentinel;
 
index 40b0e8a94713e2dcb8427b914cb614be733c605e..e85a9eda2bbf883a9beba0fd477ebb058fca052e 100644 (file)
@@ -9,6 +9,7 @@
 #include "fd-util.h"
 #include "namespace-util.h"
 #include "process-util.h"
+#include "string-util.h"
 #include "util.h"
 
 int bus_container_connect_socket(sd_bus *b) {
@@ -24,10 +25,15 @@ int bus_container_connect_socket(sd_bus *b) {
         assert(b->nspid > 0 || b->machine);
 
         if (b->nspid <= 0) {
+                log_debug("sd-bus: connecting bus%s%s to machine %s...",
+                          b->description ? " " : "", strempty(b->description), b->machine);
+
                 r = container_get_leader(b->machine, &b->nspid);
                 if (r < 0)
                         return r;
-        }
+        } else
+                log_debug("sd-bus: connecting bus%s%s to namespace of PID "PID_FMT"...",
+                          b->description ? " " : "", strempty(b->description), b->nspid);
 
         r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
         if (r < 0)
index 55e35cd902ee960e20bb13271aa69ce0e0df89c5..f966dda2294563ff5aca14e94a25454ab272ccc6 100644 (file)
@@ -4795,8 +4795,13 @@ _public_ int sd_bus_message_read_array(
         assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
 
         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
-        if (r <= 0)
+        if (r < 0)
                 return r;
+        if (r == 0) {
+                *ptr = NULL;
+                *size = 0;
+                return 0;
+        }
 
         c = message_get_last_container(m);
 
index de36a1f278af70654956e9b9467b98c529984939..1a040157f40a8fcd61b1b682c6a655fe3284ea9c 100644 (file)
@@ -885,6 +885,13 @@ int bus_socket_connect(sd_bus *b) {
                 assert(b->output_fd < 0);
                 assert(b->sockaddr.sa.sa_family != AF_UNSPEC);
 
+                if (DEBUG_LOGGING) {
+                        _cleanup_free_ char *pretty = NULL;
+                        (void) sockaddr_pretty(&b->sockaddr.sa, b->sockaddr_size, false, true, &pretty);
+                        log_debug("sd-bus: starting bus%s%s by connecting to %s...",
+                                  b->description ? " " : "", strempty(b->description), strnull(pretty));
+                }
+
                 b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
                 if (b->input_fd < 0)
                         return -errno;
@@ -956,6 +963,9 @@ int bus_socket_exec(sd_bus *b) {
         assert(b->exec_path);
         assert(b->busexec_pid == 0);
 
+        log_debug("sd-bus: starting bus%s%s with %s...",
+                  b->description ? " " : "", strempty(b->description), b->exec_path);
+
         r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s);
         if (r < 0)
                 return -errno;
index 015a215c420ae3f6b790cc11e52330ad7b0a952a..2337a4b3de74e6b465ffdc10f9c1fb8b61f83ab3 100644 (file)
@@ -1155,6 +1155,16 @@ static int bus_start_fd(sd_bus *b) {
         assert(b->input_fd >= 0);
         assert(b->output_fd >= 0);
 
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *pi = NULL, *po = NULL;
+                (void) fd_get_path(b->input_fd, &pi);
+                (void) fd_get_path(b->output_fd, &po);
+                log_debug("sd-bus: starting bus%s%s on fds %d/%d (%s, %s)...",
+                          b->description ? " " : "", strempty(b->description),
+                          b->input_fd, b->output_fd,
+                          pi ?: "???", po ?: "???");
+        }
+
         r = fd_nonblock(b->input_fd, true);
         if (r < 0)
                 return r;
@@ -1330,7 +1340,8 @@ int bus_set_address_user(sd_bus *b) {
 
                 e = secure_getenv("XDG_RUNTIME_DIR");
                 if (!e)
-                        return -ENOENT;
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
+                                               "sd-bus: $XDG_RUNTIME_DIR not set, cannot connect to user bus.");
 
                 ee = bus_address_escape(e);
                 if (!ee)
@@ -2120,12 +2131,13 @@ int bus_ensure_running(sd_bus *bus) {
 
         assert(bus);
 
-        if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING))
-                return -ENOTCONN;
         if (bus->state == BUS_RUNNING)
                 return 1;
 
         for (;;) {
+                if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING))
+                        return -ENOTCONN;
+
                 r = sd_bus_process(bus, NULL);
                 if (r < 0)
                         return r;
index f67d06ecec0d8475c643c671bfcfc5e21f4813d8..1497dc696f2f82a40b9809dad39aff48e5dbc644 100644 (file)
@@ -285,8 +285,7 @@ static void* client1(void *p) {
         assert_se(streq(hello, "hello"));
 
         if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
-                log_error_errno(errno, "Failed to allocate pipe: %m");
-                r = -errno;
+                r = log_error_errno(errno, "Failed to allocate pipe: %m");
                 goto finish;
         }
 
index 99d335e3fceb852a8556f5a68e7046da84a14a82..86a2407507ed514a67e7f4c6ad75bb49850ae68e 100644 (file)
@@ -23,7 +23,7 @@ static int test_bus_open(void) {
         int r;
 
         r = sd_bus_open_user(&bus);
-        if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
+        if (IN_SET(r, -ECONNREFUSED, -ENOENT, -ENOMEDIUM)) {
                 r = sd_bus_open_system(&bus);
                 if (IN_SET(r, -ECONNREFUSED, -ENOENT))
                         return r;
index 68a0010368833fc55180ee6795cc5ba807616872..5adcf948ddb6c8f537f9cd7677a602eb1d3c466b 100644 (file)
@@ -55,7 +55,7 @@ int main(int argc, char *argv[]) {
         assert_se(r >= 0);
 
         r = sd_bus_open_user(&a);
-        if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
+        if (IN_SET(r, -ECONNREFUSED, -ENOENT, -ENOMEDIUM)) {
                 r = sd_bus_open_system(&a);
                 if (IN_SET(r, -ECONNREFUSED, -ENOENT))
                         return log_tests_skipped("Failed to connect to bus");
index f3bac17ca3a7720607a82d69dfd907fe61ac6ef1..2d1ce7988873366d697dac7bf834b18ed25131bc 100644 (file)
@@ -118,7 +118,7 @@ _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumer
         else
                 hashmap = &enumerator->nomatch_sysattr;
 
-        r = hashmap_put_strdup(hashmap, sysattr, value);
+        r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
         if (r <= 0)
                 return r;
 
@@ -133,7 +133,7 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
         assert_return(enumerator, -EINVAL);
         assert_return(property, -EINVAL);
 
-        r = hashmap_put_strdup(&enumerator->match_property, property, value);
+        r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
         if (r <= 0)
                 return r;
 
index 08eb9b6a611e268c08c64654fcd215085058c798..a8a30d825ebee317f6dcefa42948cd81003bcac5 100644 (file)
@@ -60,6 +60,7 @@ struct sd_event_source {
         bool pending:1;
         bool dispatching:1;
         bool floating:1;
+        bool exit_on_failure:1;
 
         int64_t priority;
         unsigned pending_index;
index 7dd43f2ddc56cbfe154e595976474ac827c497e3..5e770c83b7af85ec104b49db9941e645c7df47ad 100644 (file)
@@ -399,13 +399,11 @@ static int source_io_register(
                 .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
                 .data.ptr = s,
         };
-        int r;
 
-        r = epoll_ctl(s->event->epoll_fd,
+        if (epoll_ctl(s->event->epoll_fd,
                       s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
                       s->io.fd,
-                      &ev);
-        if (r < 0)
+                      &ev) < 0)
                 return -errno;
 
         s->io.registered = true;
@@ -616,8 +614,7 @@ static int event_make_signal_data(
                 .data.ptr = d,
         };
 
-        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev);
-        if (r < 0)  {
+        if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) {
                 r = -errno;
                 goto fail;
         }
@@ -972,6 +969,12 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t
         return s;
 }
 
+static int io_exit_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        assert(s);
+
+        return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
 _public_ int sd_event_add_io(
                 sd_event *e,
                 sd_event_source **ret,
@@ -987,10 +990,12 @@ _public_ int sd_event_add_io(
         assert_return(e = event_resolve(e), -ENOPKG);
         assert_return(fd >= 0, -EBADF);
         assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = io_exit_callback;
+
         s = source_new(e, !ret, SOURCE_IO);
         if (!s)
                 return -ENOMEM;
@@ -1044,7 +1049,6 @@ static int event_setup_timer_fd(
                 return 0;
 
         _cleanup_close_ int fd = -1;
-        int r;
 
         fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
         if (fd < 0)
@@ -1057,8 +1061,7 @@ static int event_setup_timer_fd(
                 .data.ptr = d,
         };
 
-        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
-        if (r < 0)
+        if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
                 return -errno;
 
         d->fd = TAKE_FD(fd);
@@ -1235,6 +1238,12 @@ _public_ int sd_event_add_signal(
         return 0;
 }
 
+static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *userdata) {
+        assert(s);
+
+        return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
 static bool shall_use_pidfd(void) {
         /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
         return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
@@ -1256,10 +1265,12 @@ _public_ int sd_event_add_child(
         assert_return(pid > 1, -EINVAL);
         assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
         assert_return(options != 0, -EINVAL);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = child_exit_callback;
+
         if (e->n_enabled_child_sources == 0) {
                 /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
                  * for compatibility with pre-pidfd and because we don't want the reap the child processes
@@ -1357,10 +1368,12 @@ _public_ int sd_event_add_child_pidfd(
         assert_return(pidfd >= 0, -EBADF);
         assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
         assert_return(options != 0, -EINVAL);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = child_exit_callback;
+
         if (e->n_enabled_child_sources == 0) {
                 r = signal_is_blocked(SIGCHLD);
                 if (r < 0)
@@ -1426,6 +1439,12 @@ _public_ int sd_event_add_child_pidfd(
         return 0;
 }
 
+static int generic_exit_callback(sd_event_source *s, void *userdata) {
+        assert(s);
+
+        return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
 _public_ int sd_event_add_defer(
                 sd_event *e,
                 sd_event_source **ret,
@@ -1437,10 +1456,12 @@ _public_ int sd_event_add_defer(
 
         assert_return(e, -EINVAL);
         assert_return(e = event_resolve(e), -ENOPKG);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = generic_exit_callback;
+
         s = source_new(e, !ret, SOURCE_DEFER);
         if (!s)
                 return -ENOMEM;
@@ -1471,10 +1492,12 @@ _public_ int sd_event_add_post(
 
         assert_return(e, -EINVAL);
         assert_return(e = event_resolve(e), -ENOPKG);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = generic_exit_callback;
+
         s = source_new(e, !ret, SOURCE_POST);
         if (!s)
                 return -ENOMEM;
@@ -1826,6 +1849,12 @@ static int inode_data_realize_watch(sd_event *e, struct inode_data *d) {
         return 1;
 }
 
+static int inotify_exit_callback(sd_event_source *s, const struct inotify_event *event, void *userdata) {
+        assert(s);
+
+        return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
 _public_ int sd_event_add_inotify(
                 sd_event *e,
                 sd_event_source **ret,
@@ -1844,10 +1873,12 @@ _public_ int sd_event_add_inotify(
         assert_return(e, -EINVAL);
         assert_return(e = event_resolve(e), -ENOPKG);
         assert_return(path, -EINVAL);
-        assert_return(callback, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (!callback)
+                callback = inotify_exit_callback;
+
         /* Refuse IN_MASK_ADD since we coalesce watches on the same inode, and hence really don't want to merge
          * masks. Or in other words, this whole code exists only to manage IN_MASK_ADD type operations for you, hence
          * the user can't use them for us. */
@@ -2740,7 +2771,6 @@ static int event_arm_timer(
         struct itimerspec its = {};
         sd_event_source *a, *b;
         usec_t t;
-        int r;
 
         assert(e);
         assert(d);
@@ -2760,9 +2790,8 @@ static int event_arm_timer(
                         return 0;
 
                 /* disarm */
-                r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL);
-                if (r < 0)
-                        return r;
+                if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
+                        return -errno;
 
                 d->next = USEC_INFINITY;
                 return 0;
@@ -2784,8 +2813,7 @@ static int event_arm_timer(
         } else
                 timespec_store(&its.it_value, t);
 
-        r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL);
-        if (r < 0)
+        if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
                 return -errno;
 
         d->next = t;
@@ -2910,9 +2938,8 @@ static int process_child(sd_event *e) {
                         continue;
 
                 zero(s->child.siginfo);
-                r = waitid(P_PID, s->child.pid, &s->child.siginfo,
-                           WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
-                if (r < 0)
+                if (waitid(P_PID, s->child.pid, &s->child.siginfo,
+                           WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0)
                         return -errno;
 
                 if (s->child.siginfo.si_pid != 0) {
@@ -3183,16 +3210,21 @@ static int process_inotify(sd_event *e) {
 }
 
 static int source_dispatch(sd_event_source *s) {
+        _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL;
         EventSourceType saved_type;
         int r = 0;
 
         assert(s);
         assert(s->pending || s->type == SOURCE_EXIT);
 
-        /* Save the event source type, here, so that we still know it after the event callback which might invalidate
-         * the event. */
+        /* Save the event source type, here, so that we still know it after the event callback which might
+         * invalidate the event. */
         saved_type = s->type;
 
+        /* Similar, store a reference to the event loop object, so that we can still access it after the
+         * callback might have invalidated/disconnected the event source. */
+        saved_event = sd_event_ref(s->event);
+
         if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
                 r = source_set_pending(s, false);
                 if (r < 0)
@@ -3299,9 +3331,15 @@ static int source_dispatch(sd_event_source *s) {
 
         s->dispatching = false;
 
-        if (r < 0)
-                log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m",
-                                strna(s->description), event_source_type_to_string(saved_type));
+        if (r < 0) {
+                log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m",
+                                strna(s->description),
+                                event_source_type_to_string(saved_type),
+                                s->exit_on_failure ? "exiting" : "disabling");
+
+                if (s->exit_on_failure)
+                        (void) sd_event_exit(saved_event, r);
+        }
 
         if (s->n_ref == 0)
                 source_free(s);
@@ -3334,9 +3372,15 @@ static int event_prepare(sd_event *e) {
                 r = s->prepare(s, s->userdata);
                 s->dispatching = false;
 
-                if (r < 0)
-                        log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, disabling: %m",
-                                        strna(s->description), event_source_type_to_string(s->type));
+                if (r < 0) {
+                        log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, %s: %m",
+                                        strna(s->description),
+                                        event_source_type_to_string(s->type),
+                                        s->exit_on_failure ? "exiting" : "disabling");
+
+                        if (s->exit_on_failure)
+                                (void) sd_event_exit(e, r);
+                }
 
                 if (s->n_ref == 0)
                         source_free(s);
@@ -3386,7 +3430,6 @@ static sd_event_source* event_next_pending(sd_event *e) {
 static int arm_watchdog(sd_event *e) {
         struct itimerspec its = {};
         usec_t t;
-        int r;
 
         assert(e);
         assert(e->watchdog_fd >= 0);
@@ -3402,8 +3445,7 @@ static int arm_watchdog(sd_event *e) {
         if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
                 its.it_value.tv_nsec = 1;
 
-        r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL);
-        if (r < 0)
+        if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
                 return -errno;
 
         return 0;
@@ -3756,7 +3798,6 @@ _public_ int sd_event_loop(sd_event *e) {
 }
 
 _public_ int sd_event_get_fd(sd_event *e) {
-
         assert_return(e, -EINVAL);
         assert_return(e = event_resolve(e), -ENOPKG);
         assert_return(!event_pid_changed(e), -ECHILD);
@@ -3813,8 +3854,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
                 return -EOPNOTSUPP;
 
         if (!triple_timestamp_is_set(&e->timestamp)) {
-                /* Implicitly fall back to now() if we never ran
-                 * before and thus have no cached time. */
+                /* Implicitly fall back to now() if we never ran before and thus have no cached time. */
                 *usec = now(clock);
                 return 1;
         }
@@ -3893,8 +3933,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
                         .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG),
                 };
 
-                r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev);
-                if (r < 0) {
+                if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev) < 0) {
                         r = -errno;
                         goto fail;
                 }
@@ -3974,3 +4013,21 @@ _public_ int sd_event_source_set_floating(sd_event_source *s, int b) {
 
         return 1;
 }
+
+_public_ int sd_event_source_get_exit_on_failure(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+
+        return s->exit_on_failure;
+}
+
+_public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+
+        if (s->exit_on_failure == !!b)
+                return 0;
+
+        s->exit_on_failure = b;
+        return 1;
+}
index 54d293ca4619153ca9fd5434783597c1604e38bc..b623972365677fca509bf6c42a46fcc7d7f1530c 100644 (file)
@@ -548,10 +548,9 @@ static void test_pidfd(void) {
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
 
         pid = fork();
-        if (pid == 0) {
+        if (pid == 0)
                 /* child */
                 _exit(66);
-        }
 
         assert_se(pid > 1);
 
index 1b642b6851491e84fa1b30d469b02425d97654b2..2266b67adbd7009ff71b85eabc793bdf74aaf09c 100644 (file)
@@ -105,12 +105,10 @@ static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
 }
 
 static void trie_node_cleanup(struct trie_node *node) {
-        size_t i;
-
         if (!node)
                 return;
 
-        for (i = 0; i < node->children_count; i++)
+        for (size_t i = 0; i < node->children_count; i++)
                 trie_node_cleanup(node->children[i].child);
         free(node->children);
         free(node->values);
@@ -191,10 +189,9 @@ static int trie_node_add_value(struct trie *trie, struct trie_node *node,
 static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
                        const char *key, const char *value,
                        const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
-        size_t i = 0;
         int r = 0;
 
-        for (;;) {
+        for (size_t i = 0;; i++) {
                 size_t p;
                 uint8_t c;
                 struct trie_node *child;
@@ -273,7 +270,6 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
                 }
 
                 node = child;
-                i++;
         }
 }
 
@@ -289,20 +285,17 @@ struct trie_f {
 
 /* calculate the storage space for the nodes, children arrays, value arrays */
 static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, bool compat) {
-        uint64_t i;
-
-        for (i = 0; i < node->children_count; i++)
+        for (uint64_t i = 0; i < node->children_count; i++)
                 trie_store_nodes_size(trie, node->children[i].child, compat);
 
         trie->strings_off += sizeof(struct trie_node_f);
-        for (i = 0; i < node->children_count; i++)
+        for (uint64_t i = 0; i < node->children_count; i++)
                 trie->strings_off += sizeof(struct trie_child_entry_f);
-        for (i = 0; i < node->values_count; i++)
+        for (uint64_t i = 0; i < node->values_count; i++)
                 trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f);
 }
 
 static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) {
-        uint64_t i;
         struct trie_node_f n = {
                 .prefix_off = htole64(trie->strings_off + node->prefix_off),
                 .children_count = node->children_count,
@@ -318,7 +311,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
         }
 
         /* post-order recursion */
-        for (i = 0; i < node->children_count; i++) {
+        for (uint64_t i = 0; i < node->children_count; i++) {
                 int64_t child_off;
 
                 child_off = trie_store_nodes(trie, node->children[i].child, compat);
@@ -343,7 +336,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
         }
 
         /* append values array */
-        for (i = 0; i < node->values_count; i++) {
+        for (uint64_t i = 0; i < node->values_count; i++) {
                 struct trie_value_entry2_f v = {
                         .key_off = htole64(trie->strings_off + node->values[i].key_off),
                         .value_off = htole64(trie->strings_off + node->values[i].value_off),
@@ -447,7 +440,7 @@ static int insert_data(struct trie *trie, char **match_list, char *line, const c
         value = strchr(line, '=');
         if (!value)
                 return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
-                                  "Key-value pair expected but got \"%s\", ignoring", line);
+                                  "Key-value pair expected but got \"%s\", ignoring.", line);
 
         value[0] = '\0';
         value++;
@@ -456,10 +449,9 @@ static int insert_data(struct trie *trie, char **match_list, char *line, const c
         while (isblank(line[0]) && isblank(line[1]))
                 line++;
 
-        if (isempty(line + 1) || isempty(value))
+        if (isempty(line + 1))
                 return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
-                                  "Empty %s in \"%s=%s\", ignoring",
-                                  isempty(line + 1) ? "key" : "value",
+                                  "Empty key in \"%s=%s\", ignoring.",
                                   line, value);
 
         STRV_FOREACH(entry, match_list)
@@ -494,7 +486,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
                 if (r == 0)
                         break;
 
-                ++line_number;
+                line_number ++;
 
                 /* comment line */
                 if (line[0] == '#')
@@ -518,7 +510,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
 
                         if (line[0] == ' ') {
                                 r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
-                                               "Match expected but got indented property \"%s\", ignoring line", line);
+                                               "Match expected but got indented property \"%s\", ignoring line.", line);
                                 break;
                         }
 
@@ -534,7 +526,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
                 case HW_MATCH:
                         if (len == 0) {
                                 r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
-                                               "Property expected, ignoring record with no properties");
+                                               "Property expected, ignoring record with no properties.");
                                 state = HW_NONE;
                                 match_list = strv_free(match_list);
                                 break;
@@ -566,7 +558,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
 
                         if (line[0] != ' ') {
                                 r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
-                                               "Property or empty line expected, got \"%s\", ignoring record", line);
+                                               "Property or empty line expected, got \"%s\", ignoring record.", line);
                                 state = HW_NONE;
                                 match_list = strv_free(match_list);
                                 break;
@@ -581,7 +573,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
 
         if (state == HW_MATCH)
                 log_syntax(NULL, LOG_WARNING, filename, line_number, 0,
-                           "Property expected, ignoring record with no properties");
+                           "Property expected, ignoring record with no properties.");
 
         return r;
 }
index b3febdbb313376c8bbb00c823466bc10450f598b..0e326f3d223842465788c8d5d6f1fdf96f78b01b 100644 (file)
@@ -343,10 +343,10 @@ _public_ int sd_hwdb_new(sd_hwdb **ret) {
                 return log_debug_errno(errno, "Failed to map %s: %m", hwdb_bin_path);
 
         if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
-            (size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
-                log_debug("Failed to recognize the format of %s", hwdb_bin_path);
-                return -EINVAL;
-        }
+            (size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size))
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Failed to recognize the format of %s",
+                                       hwdb_bin_path);
 
         log_debug("=== trie on-disk ===");
         log_debug("tool version:          %"PRIu64, le64toh(hwdb->head->tool_version));
index 335f22b9208da3b797b8c9e2b99435f872184b3c..ebbfb2d32ebae6bd400de1a6979f36e70c642e2f 100644 (file)
@@ -10,6 +10,7 @@
 #include "id128-util.h"
 #include "io-util.h"
 #include "stdio-util.h"
+#include "string-util.h"
 
 char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) {
         unsigned n, k = 0;
@@ -97,6 +98,11 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
 
         switch (l) {
 
+        case 13:
+        case 14:
+                /* Treat an "uninitialized" id file like an empty one */
+                return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
+
         case 33: /* plain UUID with trailing newline */
                 if (buffer[32] != '\n')
                         return -EINVAL;
@@ -115,7 +121,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
 
                 _fallthrough_;
         case 36: /* RFC UUID without trailing newline */
-                if (f == ID128_PLAIN)
+                if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
                         return -EINVAL;
 
                 buffer[36] = 0;
index 1901bf119fffb565b8606fc84cd15aa73102bd6d..1453c00f2f1ce709462e932793f0364a5e53e0d5 100644 (file)
@@ -17,6 +17,10 @@ bool id128_is_valid(const char *s) _pure_;
 typedef enum Id128Format {
         ID128_ANY,
         ID128_PLAIN,  /* formatted as 32 hex chars as-is */
+        ID128_PLAIN_OR_UNINIT,  /* formatted as 32 hex chars as-is; allow special "uninitialized"
+                                 * value when reading from file (id128_read() and id128_read_fd()).
+                                 *
+                                 * This format should be used when reading a machine-id file. */
         ID128_UUID,   /* formatted as 36 character uuid string */
         _ID128_FORMAT_MAX,
 } Id128Format;
index c0c77e04714bc1c54d8a29f8e27445554845ad59..0494fc77ba18af5dd5c741d6bc758910196ffdee 100644 (file)
@@ -5,21 +5,22 @@
 #include "sd-login.h"
 
 #include "alloc-util.h"
+#include "errno-list.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "log.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
-#include "util.h"
+#include "user-util.h"
 
 static char* format_uids(char **buf, uid_t* uids, int count) {
-        int pos = 0, k, inc;
+        int pos = 0, inc;
         size_t size = (DECIMAL_STR_MAX(uid_t) + 1) * count + 1;
 
         assert_se(*buf = malloc(size));
 
-        for (k = 0; k < count; k++) {
+        for (int k = 0; k < count; k++) {
                 sprintf(*buf + pos, "%s"UID_FMT"%n", k > 0 ? " " : "", uids[k], &inc);
                 pos += inc;
         }
@@ -30,6 +31,10 @@ static char* format_uids(char **buf, uid_t* uids, int count) {
         return *buf;
 }
 
+static const char *e(int r) {
+        return r == 0 ? "OK" : errno_to_name(r);
+}
+
 static void test_login(void) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
         _cleanup_free_ char *pp = NULL, *qq = NULL,
@@ -39,65 +44,71 @@ static void test_login(void) {
                 *seat = NULL, *session = NULL,
                 *unit = NULL, *user_unit = NULL, *slice = NULL;
         int r;
-        uid_t u, u2;
-        char *t, **seats, **sessions;
+        uid_t u, u2 = UID_INVALID;
+        char *t, **seats = NULL, **sessions = NULL;
 
         r = sd_pid_get_unit(0, &unit);
-        assert_se(r >= 0 || r == -ENODATA);
-        log_info("sd_pid_get_unit(0, …) → \"%s\"", strna(unit));
+        log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit));
+        assert_se(IN_SET(r, 0, -ENODATA));
 
         r = sd_pid_get_user_unit(0, &user_unit);
-        assert_se(r >= 0 || r == -ENODATA);
-        log_info("sd_pid_get_user_unit(0, …) → \"%s\"", strna(user_unit));
+        log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit));
+        assert_se(IN_SET(r, 0, -ENODATA));
 
         r = sd_pid_get_slice(0, &slice);
-        assert_se(r >= 0 || r == -ENODATA);
-        log_info("sd_pid_get_slice(0, …) → \"%s\"", strna(slice));
+        log_info("sd_pid_get_slice(0, …) → %s / \"%s\"", e(r), strnull(slice));
+        assert_se(IN_SET(r, 0, -ENODATA));
+
+        r = sd_pid_get_owner_uid(0, &u2);
+        log_info("sd_pid_get_owner_uid(0, …) → %s / "UID_FMT, e(r), u2);
+        assert_se(IN_SET(r, 0, -ENODATA));
 
         r = sd_pid_get_session(0, &session);
-        if (r < 0) {
-                log_warning_errno(r, "sd_pid_get_session(0, …): %m");
-                if (r == -ENODATA)
-                        log_info("Seems we are not running in a session, skipping some tests.");
-        } else {
-                log_info("sd_pid_get_session(0, …) → \"%s\"", session);
-
-                assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
-                log_info("sd_pid_get_owner_uid(0, …) → "UID_FMT, u2);
-
-                assert_se(sd_pid_get_cgroup(0, &cgroup) == 0);
-                log_info("sd_pid_get_cgroup(0, …) → \"%s\"", cgroup);
-
-                r = sd_uid_get_display(u2, &display_session);
-                assert_se(r >= 0 || r == -ENODATA);
-                log_info("sd_uid_get_display("UID_FMT", …) → \"%s\"",
-                         u2, strnull(display_session));
-
-                assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
-                sd_peer_get_session(pair[0], &pp);
-                sd_peer_get_session(pair[1], &qq);
-                assert_se(streq_ptr(pp, qq));
-
-                r = sd_uid_get_sessions(u2, false, &sessions);
+        log_info("sd_pid_get_session(0, …) → %s / \"%s\"", e(r), strnull(session));
+
+        r = sd_pid_get_cgroup(0, &cgroup);
+        log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup));
+        assert_se(r == 0);
+
+        r = sd_uid_get_display(u2, &display_session);
+        log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));
+        if (u2 == UID_INVALID)
+                assert_se(r == -EINVAL);
+        else
+                assert_se(IN_SET(r, 0, -ENODATA));
+
+        assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
+        sd_peer_get_session(pair[0], &pp);
+        sd_peer_get_session(pair[1], &qq);
+        assert_se(streq_ptr(pp, qq));
+
+        r = sd_uid_get_sessions(u2, false, &sessions);
+        assert_se(t = strv_join(sessions, " "));
+        log_info("sd_uid_get_sessions("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
+        if (u2 == UID_INVALID)
+                assert_se(r == -EINVAL);
+        else {
                 assert_se(r >= 0);
                 assert_se(r == (int) strv_length(sessions));
-                assert_se(t = strv_join(sessions, " "));
-                strv_free(sessions);
-                log_info("sd_uid_get_sessions("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
-                free(t);
+        }
+        sessions = strv_free(sessions);
+        free(t);
 
-                assert_se(r == sd_uid_get_sessions(u2, false, NULL));
+        assert_se(r == sd_uid_get_sessions(u2, false, NULL));
 
-                r = sd_uid_get_seats(u2, false, &seats);
+        r = sd_uid_get_seats(u2, false, &seats);
+        assert_se(t = strv_join(seats, " "));
+        log_info("sd_uid_get_seats("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
+        if (u2 == UID_INVALID)
+                assert_se(r == -EINVAL);
+        else {
                 assert_se(r >= 0);
                 assert_se(r == (int) strv_length(seats));
-                assert_se(t = strv_join(seats, " "));
-                strv_free(seats);
-                log_info("sd_uid_get_seats("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
-                free(t);
-
-                assert_se(r == sd_uid_get_seats(u2, false, NULL));
         }
+        seats = strv_free(seats);
+        free(t);
+
+        assert_se(r == sd_uid_get_seats(u2, false, NULL));
 
         if (session) {
                 r = sd_session_is_active(session);
@@ -109,7 +120,7 @@ static void test_login(void) {
                 log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
 
                 r = sd_session_get_state(session, &state);
-                assert_se(r >= 0);
+                assert_se(r == 0);
                 log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
 
                 assert_se(sd_session_get_uid(session, &u) >= 0);
@@ -123,16 +134,16 @@ static void test_login(void) {
                 log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
 
                 r = sd_session_get_display(session, &display);
-                assert_se(r >= 0 || r == -ENODATA);
+                assert_se(IN_SET(r, 0, -ENODATA));
                 log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
 
                 r = sd_session_get_remote_user(session, &remote_user);
-                assert_se(r >= 0 || r == -ENODATA);
+                assert_se(IN_SET(r, 0, -ENODATA));
                 log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
                          session, strna(remote_user));
 
                 r = sd_session_get_remote_host(session, &remote_host);
-                assert_se(r >= 0 || r == -ENODATA);
+                assert_se(IN_SET(r, 0, -ENODATA));
                 log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
                          session, strna(remote_host));
 
@@ -161,7 +172,7 @@ static void test_login(void) {
                         assert_se(r == -ENODATA);
                 }
 
-                assert_se(sd_uid_get_state(u, &state2) >= 0);
+                assert_se(sd_uid_get_state(u, &state2) == 0);
                 log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
         }
 
@@ -173,11 +184,11 @@ static void test_login(void) {
                 assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
 
                 r = sd_seat_get_active(seat, &session2, &u2);
-                assert_se(r >= 0);
+                assert_se(r == 0);
                 log_info("sd_seat_get_active(\"%s\", …) → \"%s\", "UID_FMT, seat, session2, u2);
 
                 r = sd_uid_is_on_seat(u, 1, seat);
-                assert_se(r >= 0);
+                assert_se(IN_SET(r, 0, 1));
                 assert_se(!!r == streq(session, session2));
 
                 r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
@@ -185,8 +196,8 @@ static void test_login(void) {
                 assert_se(r == (int) strv_length(sessions));
                 assert_se(t = strv_join(sessions, " "));
                 strv_free(sessions);
-                log_info("sd_seat_get_sessions(\"%s\", …) → %i, \"%s\", [%i] {%s}",
-                         seat, r, t, n, format_uids(&buf, uids, n));
+                log_info("sd_seat_get_sessions(\"%s\", …) → %s, \"%s\", [%u] {%s}",
+                         seat, e(r), t, n, format_uids(&buf, uids, n));
                 free(t);
 
                 assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r);
@@ -204,7 +215,7 @@ static void test_login(void) {
 
         r = sd_seat_get_active(NULL, &t, NULL);
         assert_se(IN_SET(r, 0, -ENODATA));
-        log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s", strnull(t));
+        log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t));
         free(t);
 
         r = sd_get_sessions(&sessions);
@@ -244,13 +255,11 @@ static void test_login(void) {
 
 static void test_monitor(void) {
         sd_login_monitor *m = NULL;
-        unsigned n;
         int r;
 
-        r = sd_login_monitor_new("session", &m);
-        assert_se(r >= 0);
+        assert_se(sd_login_monitor_new("session", &m) == 0);
 
-        for (n = 0; n < 5; n++) {
+        for (unsigned n = 0; n < 5; n++) {
                 struct pollfd pollfd = {};
                 usec_t timeout, nw;
 
index d6bf31efc7a196f3708fcbb2db1ea6c8f9700e65..da4f5ba6888f79595f3bddd81064026d25ec6ba2 100644 (file)
@@ -694,6 +694,30 @@ int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t s
         return r;
 }
 
+int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
+        void *attr_data, *data;
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
+        if (r < 0)
+                return r;
+
+        if (ret_data) {
+                data = memdup(attr_data, r);
+                if (!data)
+                        return -ENOMEM;
+
+                *ret_data = data;
+        }
+
+        if (ret_size)
+                *ret_size = r;
+
+        return r;
+}
+
 int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
         void *attr_data;
         char *str;
@@ -862,11 +886,12 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ
         return 0;
 }
 
-int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
-        int r;
+int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data) {
         void *attr_data;
+        int r;
 
         assert_return(m, -EINVAL);
+        assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
 
         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
         if (r < 0)
@@ -875,35 +900,35 @@ int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type,
         r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
-        else if ((size_t) r < sizeof(struct in_addr))
+        else if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
                 return -EIO;
 
         if (data)
-                memcpy(data, attr_data, sizeof(struct in_addr));
+                memcpy(data, attr_data, FAMILY_ADDRESS_SIZE(family));
 
         return 0;
 }
 
-int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
+int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
+        union in_addr_union u;
         int r;
-        void *attr_data;
 
-        assert_return(m, -EINVAL);
+        r = netlink_message_read_in_addr_union(m, type, AF_INET, &u);
+        if (r >= 0 && data)
+                *data = u.in;
 
-        r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
-        if (r < 0)
-                return r;
+        return r;
+}
 
-        r = netlink_message_read_internal(m, type, &attr_data, NULL);
-        if (r < 0)
-                return r;
-        else if ((size_t) r < sizeof(struct in6_addr))
-                return -EIO;
+int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
+        union in_addr_union u;
+        int r;
 
-        if (data)
-                memcpy(data, attr_data, sizeof(struct in6_addr));
+        r = netlink_message_read_in_addr_union(m, type, AF_INET6, &u);
+        if (r >= 0 && data)
+                *data = u.in6;
 
-        return 0;
+        return r;
 }
 
 int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret) {
index 9c9471eadcfdef22516235671087a95cc4e4c2e9..5f5a1558a101d4d0041dfbdd2e796bb42fbec9be 100644 (file)
@@ -716,7 +716,7 @@ static const NLType rtnl_route_types[] = {
         [RTA_TABLE]             = { .type = NETLINK_TYPE_U32 },
         [RTA_MARK]              = { .type = NETLINK_TYPE_U32 },
         [RTA_MFC_STATS]         = { .type = NETLINK_TYPE_U64 },
-        [RTA_VIA]               = { .type = NETLINK_TYPE_U32 },
+        [RTA_VIA]               = { /* See struct rtvia */ },
         [RTA_NEWDST]            = { .type = NETLINK_TYPE_U32 },
         [RTA_PREF]              = { .type = NETLINK_TYPE_U8 },
         [RTA_EXPIRES]           = { .type = NETLINK_TYPE_U32 },
index f045e794b6e7d8de2cf108f545dcc3da77a5afa8..f89340058078d270152ce40135b2f212cc3290ab 100644 (file)
@@ -368,3 +368,80 @@ int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void
 
         return 0;
 }
+
+int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
+        _cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
+        int r;
+
+        assert(rtnh);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+
+        if (size < sizeof(struct rtnexthop))
+                return -EBADMSG;
+
+        for (; size >= sizeof(struct rtnexthop); ) {
+                _cleanup_free_ MultipathRoute *m = NULL;
+
+                if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
+                        return -EBADMSG;
+
+                if (rtnh->rtnh_len < sizeof(struct rtnexthop))
+                        return -EBADMSG;
+
+                m = new(MultipathRoute, 1);
+                if (!m)
+                        return -ENOMEM;
+
+                *m = (MultipathRoute) {
+                        .ifindex = rtnh->rtnh_ifindex,
+                        .weight = rtnh->rtnh_hops == 0 ? 0 : rtnh->rtnh_hops + 1,
+                };
+
+                if (rtnh->rtnh_len > sizeof(struct rtnexthop)) {
+                        size_t len = rtnh->rtnh_len - sizeof(struct rtnexthop);
+
+                        for (struct rtattr *attr = RTNH_DATA(rtnh); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
+                                if (attr->rta_type == RTA_GATEWAY) {
+                                        if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(family)))
+                                                return -EBADMSG;
+
+                                        m->gateway.family = family;
+                                        memcpy(&m->gateway.address, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(family));
+                                        break;
+                                } else if (attr->rta_type == RTA_VIA) {
+                                        uint16_t gw_family;
+
+                                        if (family != AF_INET)
+                                                return -EINVAL;
+
+                                        if (attr->rta_len < RTA_LENGTH(sizeof(uint16_t)))
+                                                return -EBADMSG;
+
+                                        gw_family = *(uint16_t *) RTA_DATA(attr);
+
+                                        if (gw_family != AF_INET6)
+                                                return -EBADMSG;
+
+                                        if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family)))
+                                                return -EBADMSG;
+
+                                        memcpy(&m->gateway, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family));
+                                        break;
+                                }
+                        }
+                }
+
+                r = ordered_set_ensure_put(&set, NULL, m);
+                if (r < 0)
+                        return r;
+
+                TAKE_PTR(m);
+
+                size -= NLMSG_ALIGN(rtnh->rtnh_len);
+                rtnh = RTNH_NEXT(rtnh);
+        }
+
+        if (ret)
+                *ret = TAKE_PTR(set);
+        return 0;
+}
index ddf5686f1343d92873c2e135c3b64305df0a3111..2768d5fdc4db6302a7e34ebeb9f37aa60bcec588 100644 (file)
@@ -6,9 +6,22 @@
 #include "sd-netlink.h"
 
 #include "in-addr-util.h"
+#include "ordered-set.h"
 #include "socket-util.h"
 #include "util.h"
 
+/* See struct rtvia in rtnetlink.h */
+typedef struct RouteVia {
+        uint16_t family;
+        union in_addr_union address;
+} _packed_ RouteVia;
+
+typedef struct MultipathRoute {
+        RouteVia gateway;
+        int ifindex;
+        uint32_t weight;
+} MultipathRoute;
+
 int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
 uint32_t rtnl_message_get_serial(sd_netlink_message *m);
 void rtnl_message_seal(sd_netlink_message *m);
@@ -77,18 +90,22 @@ int rtnl_log_create_error(int r);
                                       userdata, 0, __func__);           \
         })
 
-#define netlink_add_match(nl, ret_slot, metch, callback, destroy_callback, userdata) \
+#define netlink_add_match(nl, ret_slot, match, callback, destroy_callback, userdata, description) \
         ({                                                              \
                 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__);               \
+                                     userdata, description);            \
         })
 
 int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data);
 int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);
 
+int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data);
+
 void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);
 int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);
+
+int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret);
index f9d79bc0d6ea43a9b79f05bce52ae911fb3ddffd..be7a4f7835deca4df58c7d3068f3c066f33ea79f 100644 (file)
@@ -139,7 +139,7 @@ static void test_route(sd_netlink *rtnl) {
                 return;
         }
 
-        addr.s_addr = htonl(INADDR_LOOPBACK);
+        addr.s_addr = htobe32(INADDR_LOOPBACK);
 
         r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr);
         if (r < 0) {
index 8377c66ae359674adbed3697264af4727bc8ee1f..627b86b3cb00c2200f2b631038f9180f134b8fce 100644 (file)
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
 
         struct sockaddr_in sa = {
                 .sin_family = AF_INET,
-                .sin_port = htons(80)
+                .sin_port = htobe16(80)
         };
 
         assert_se(sd_resolve_default(&resolve) >= 0);
index e3866eee55a711010362c229c8ed80b50e669aac..399f70fbc76aacf7b1a176f47d3746d48f47a6d0 100644 (file)
@@ -282,7 +282,7 @@ static int run(int argc, char *argv[]) {
 
         r = sd_bus_default_system(&bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to bus: %m");
+                return bus_log_connect_error(r);
 
         if (arg_action == ACTION_LIST)
                 return print_inhibitors(bus);
index bc4f25f41e8a514fc07a782283b448e8df00fd63..b7f400dc5e2c225f5cd30cf42e2f0b26d1126d79 100644 (file)
@@ -545,8 +545,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
                 printf("\t    Unit: %s\n", i.scope);
                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
 
-                if (arg_transport == BUS_TRANSPORT_LOCAL) {
-
+                if (arg_transport == BUS_TRANSPORT_LOCAL)
                         show_journal_by_unit(
                                         stdout,
                                         i.scope,
@@ -560,7 +559,6 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
                                         SD_JOURNAL_LOCAL_ONLY,
                                         true,
                                         NULL);
-                }
         }
 
         return 0;
@@ -1266,6 +1264,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -H --host=[USER@]HOST    Operate on remote host\n"
                "  -M --machine=CONTAINER   Operate on local container\n"
                "  -p --property=NAME       Show only properties by this name\n"
+               "  -P NAME                  Equivalent to --value --property=NAME\n"
                "  -a --all                 Show all properties, including empty ones\n"
                "     --value               When showing properties, only print the value\n"
                "  -l --full                Do not ellipsize output\n"
@@ -1321,7 +1320,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hp:P:als:H:M:n:o:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -1331,6 +1330,10 @@ static int parse_argv(int argc, char *argv[]) {
                 case ARG_VERSION:
                         return version();
 
+                case 'P':
+                        arg_value = true;
+                        _fallthrough_;
+
                 case 'p': {
                         r = strv_extend(&arg_property, optarg);
                         if (r < 0)
index 140953eec104afe107b581f6be3e961634d16bef..1aeacfaf2bc5d82f35d9fd533ab9510dffea923e 100644 (file)
@@ -64,7 +64,9 @@ int manager_handle_action(
 
         /* If the key handling is turned off, don't do anything */
         if (handle == HANDLE_IGNORE) {
-                log_debug("Refusing operation, as it is turned off.");
+                log_debug("Handling of %s (%s) is disabled, taking no action.",
+                          inhibit_key == 0 ? "idle timeout" : inhibit_what_to_string(inhibit_key),
+                          is_edge ? "edge" : "level");
                 return 0;
         }
 
index a685b8e5b88c82149da311403b19a498416c72d6..370604f936d80cdaa7a208e2dac58525617355b4 100644 (file)
@@ -21,6 +21,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "udev-util.h"
@@ -533,7 +534,7 @@ int manager_spawn_autovt(Manager *m, unsigned vtnr) {
                         return -EBUSY;
         }
 
-        snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
+        xsprintf(name, "autovt@tty%u.service", vtnr);
         r = sd_bus_call_method(
                         m->bus,
                         "org.freedesktop.systemd1",
index 01ffbb6bad759422991ede28516b0a322d0661fe..0f83ed99bc5016a74a2a5b6d0e5d379ec129e08a 100644 (file)
@@ -3299,6 +3299,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
         r = inhibitor_start(i);
         if (r < 0)
                 return r;
+        TAKE_PTR(i);
 
         return sd_bus_reply_method_return(message, "h", fifo_fd);
 }
index cbb5549bd819766d9cccdf5687fadbc86c80c36e..d1527380ec3b0b9de883bb3ed684d00dbf4cd7b4 100644 (file)
@@ -1089,8 +1089,8 @@ int session_create_fifo(Session *s) {
                 if (r < 0)
                         return r;
 
-                /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
-                 * sessions). */
+                /* Let's make sure we noticed dead sessions before we process new bus requests (which might
+                 * create new sessions). */
                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
                 if (r < 0)
                         return r;
@@ -1331,9 +1331,8 @@ static void session_release_controller(Session *s, bool notify) {
 
         name = s->controller;
 
-        /* By resetting the controller before releasing the devices, we won't
-         * send notification signals. This avoids sending useless notifications
-         * if the controller is released on disconnects. */
+        /* By resetting the controller before releasing the devices, we won't send notification signals.
+         * This avoids sending useless notifications if the controller is released on disconnects. */
         if (!notify)
                 s->controller = NULL;
 
@@ -1419,43 +1418,43 @@ void session_drop_controller(Session *s) {
 
 static const char* const session_state_table[_SESSION_STATE_MAX] = {
         [SESSION_OPENING] = "opening",
-        [SESSION_ONLINE] = "online",
-        [SESSION_ACTIVE] = "active",
-        [SESSION_CLOSING] = "closing"
+        [SESSION_ONLINE]  = "online",
+        [SESSION_ACTIVE]  = "active",
+        [SESSION_CLOSING] = "closing",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
 
 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
         [SESSION_UNSPECIFIED] = "unspecified",
-        [SESSION_TTY] = "tty",
-        [SESSION_X11] = "x11",
-        [SESSION_WAYLAND] = "wayland",
-        [SESSION_MIR] = "mir",
-        [SESSION_WEB] = "web",
+        [SESSION_TTY]         = "tty",
+        [SESSION_X11]         = "x11",
+        [SESSION_WAYLAND]     = "wayland",
+        [SESSION_MIR]         = "mir",
+        [SESSION_WEB]         = "web",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
 
 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
-        [SESSION_USER] = "user",
-        [SESSION_GREETER] = "greeter",
+        [SESSION_USER]        = "user",
+        [SESSION_GREETER]     = "greeter",
         [SESSION_LOCK_SCREEN] = "lock-screen",
-        [SESSION_BACKGROUND] = "background"
+        [SESSION_BACKGROUND]  = "background",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
 
 static const char* const kill_who_table[_KILL_WHO_MAX] = {
         [KILL_LEADER] = "leader",
-        [KILL_ALL] = "all"
+        [KILL_ALL]    = "all",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
 
 static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
-        [TTY_FROM_PAM] = "from-pam",
-        [TTY_FROM_UTMP] = "from-utmp",
+        [TTY_FROM_PAM]          = "from-pam",
+        [TTY_FROM_UTMP]         = "from-utmp",
         [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
 };
 
index 677a501e9821fa3d879dd51d18d7584a1afa551a..82163343d3b4ce6cc5c794f64ab641f19b437a3e 100644 (file)
@@ -14,6 +14,7 @@
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
 #include "cgroup-util.h"
+#include "daemon-util.h"
 #include "def.h"
 #include "device-util.h"
 #include "dirent-util.h"
@@ -921,14 +922,13 @@ static void manager_gc(Manager *m, bool drop_not_started) {
                 LIST_REMOVE(gc_queue, m->session_gc_queue, session);
                 session->in_gc_queue = false;
 
-                /* First, if we are not closing yet, initiate stopping */
+                /* First, if we are not closing yet, initiate stopping. */
                 if (session_may_gc(session, drop_not_started) &&
                     session_get_state(session) != SESSION_CLOSING)
                         (void) session_stop(session, /* force = */ false);
 
-                /* Normally, this should make the session referenced
-                 * again, if it doesn't then let's get rid of it
-                 * immediately */
+                /* Normally, this should make the session referenced again, if it doesn't then let's get rid
+                 * of it immediately. */
                 if (session_may_gc(session, drop_not_started)) {
                         (void) session_finalize(session);
                         session_free(session);
@@ -1156,6 +1156,7 @@ static int manager_run(Manager *m) {
 
 static int run(int argc, char *argv[]) {
         _cleanup_(manager_unrefp) Manager *m = NULL;
+        _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
         int r;
 
         log_set_facility(LOG_AUTH);
@@ -1175,9 +1176,9 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
-        /* Always create the directories people can create inotify watches in. Note that some applications might check
-         * for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make
-         * sure these directories are created early on and unconditionally. */
+        /* Always create the directories people can create inotify watches in. Note that some applications
+         * might check for the existence of /run/systemd/seats/ to determine whether logind is available, so
+         * please always make sure these directories are created early on and unconditionally. */
         (void) mkdir_label("/run/systemd/seats", 0755);
         (void) mkdir_label("/run/systemd/users", 0755);
         (void) mkdir_label("/run/systemd/sessions", 0755);
@@ -1194,19 +1195,8 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Failed to fully start up daemon: %m");
 
-        log_debug("systemd-logind running as pid "PID_FMT, getpid_cached());
-        (void) sd_notify(false,
-                         "READY=1\n"
-                         "STATUS=Processing requests...");
-
-        r = manager_run(m);
-
-        log_debug("systemd-logind stopped as pid "PID_FMT, getpid_cached());
-        (void) sd_notify(false,
-                         "STOPPING=1\n"
-                         "STATUS=Shutting down...");
-
-        return r;
+        notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
+        return manager_run(m);
 }
 
 DEFINE_MAIN_FUNCTION(run);
index 872b00c158e4df42a0a37b8fc3652bbc34503d7e..2bcd99109eb1a8014dbf4ca8fb96a910fde1146a 100644 (file)
@@ -128,7 +128,7 @@ static int run(int argc, char *argv[]) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to read machine ID back: %m");
         } else {
-                r = machine_id_setup(arg_root, SD_ID128_NULL, &id);
+                r = machine_id_setup(arg_root, false, SD_ID128_NULL, &id);
                 if (r < 0)
                         return r;
         }
index 41070dcda58b5b90d7ddd91ab502fd2e97931085..4869797b1e22c71a69c457cc6f316f66bd05f112 100644 (file)
@@ -1312,15 +1312,13 @@ static int login_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
-        if (!strv_isempty(arg_setenv) || arg_uid) {
-                log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
-                return -EINVAL;
-        }
+        if (!strv_isempty(arg_setenv) || arg_uid)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
 
-        if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
-                log_error("Login only supported on local machines.");
-                return -EOPNOTSUPP;
-        }
+        if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE))
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Login only supported on local machines.");
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
@@ -1369,10 +1367,9 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
-        if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
-                log_error("Shell only supported on local machines.");
-                return -EOPNOTSUPP;
-        }
+        if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE))
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Shell only supported on local machines.");
 
         /* Pass $TERM to shell session, if not explicitly specified. */
         if (!strv_find_prefix(arg_setenv, "TERM=")) {
@@ -1525,10 +1522,10 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
 
         if (argc > 2) {
                 b = parse_boolean(argv[2]);
-                if (b < 0) {
-                        log_error("Failed to parse boolean argument: %s", argv[2]);
-                        return -EINVAL;
-                }
+                if (b < 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Failed to parse boolean argument: %s",
+                                               argv[2]);
         }
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
@@ -1602,10 +1599,10 @@ static int start_machine(int argc, char *argv[], void *userdata) {
                 r = image_exists(bus, argv[i]);
                 if (r < 0)
                         return r;
-                if (r == 0) {
-                        log_error("Machine image '%s' does not exist.", argv[i]);
-                        return -ENXIO;
-                }
+                if (r == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
+                                               "Machine image '%s' does not exist.",
+                                               argv[i]);
 
                 r = sd_bus_call_method(
                                 bus,
@@ -1674,10 +1671,10 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
                 r = image_exists(bus, argv[i]);
                 if (r < 0)
                         return r;
-                if (r == 0) {
-                        log_error("Machine image '%s' does not exist.", argv[i]);
-                        return -ENXIO;
-                }
+                if (r == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
+                                               "Machine image '%s' does not exist.",
+                                               argv[i]);
 
                 r = sd_bus_message_append(m, "s", unit);
                 if (r < 0)
@@ -1874,10 +1871,9 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
                 local = fn;
         }
-        if (!local) {
-                log_error("Need either path or local name.");
-                return -EINVAL;
-        }
+        if (!local)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Need either path or local name.");
 
         r = tar_strip_suffixes(local, &ll);
         if (r < 0)
@@ -1885,10 +1881,10 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
         local = ll;
 
-        if (!machine_name_is_valid(local)) {
-                log_error("Local name %s is not a suitable machine name.", local);
-                return -EINVAL;
-        }
+        if (!machine_name_is_valid(local))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Local name %s is not a suitable machine name.",
+                                       local);
 
         if (path) {
                 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -1935,10 +1931,9 @@ static int import_raw(int argc, char *argv[], void *userdata) {
 
                 local = fn;
         }
-        if (!local) {
-                log_error("Need either path or local name.");
-                return -EINVAL;
-        }
+        if (!local)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Need either path or local name.");
 
         r = raw_strip_suffixes(local, &ll);
         if (r < 0)
@@ -1946,10 +1941,10 @@ static int import_raw(int argc, char *argv[], void *userdata) {
 
         local = ll;
 
-        if (!machine_name_is_valid(local)) {
-                log_error("Local name %s is not a suitable machine name.", local);
-                return -EINVAL;
-        }
+        if (!machine_name_is_valid(local))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Local name %s is not a suitable machine name.",
+                                       local);
 
         if (path) {
                 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -1996,15 +1991,14 @@ static int import_fs(int argc, char *argv[], void *userdata) {
 
                 local = fn;
         }
-        if (!local) {
-                log_error("Need either path or local name.");
-                return -EINVAL;
-        }
+        if (!local)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Need either path or local name.");
 
-        if (!machine_name_is_valid(local)) {
-                log_error("Local name %s is not a suitable machine name.", local);
-                return -EINVAL;
-        }
+        if (!machine_name_is_valid(local))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Local name %s is not a suitable machine name.",
+                                       local);
 
         if (path) {
                 fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
@@ -2054,10 +2048,9 @@ static int export_tar(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         local = argv[1];
-        if (!machine_name_is_valid(local)) {
-                log_error("Machine name %s is not valid.", local);
-                return -EINVAL;
-        }
+        if (!machine_name_is_valid(local))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Machine name %s is not valid.", local);
 
         if (argc >= 3)
                 path = argv[2];
@@ -2097,10 +2090,9 @@ static int export_raw(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         local = argv[1];
-        if (!machine_name_is_valid(local)) {
-                log_error("Machine name %s is not valid.", local);
-                return -EINVAL;
-        }
+        if (!machine_name_is_valid(local))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Machine name %s is not valid.", local);
 
         if (argc >= 3)
                 path = argv[2];
@@ -2140,10 +2132,9 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         remote = argv[1];
-        if (!http_url_is_valid(remote)) {
-                log_error("URL '%s' is not valid.", remote);
-                return -EINVAL;
-        }
+        if (!http_url_is_valid(remote))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "URL '%s' is not valid.", remote);
 
         if (argc >= 3)
                 local = argv[2];
@@ -2164,10 +2155,10 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local name %s is not a suitable machine name.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local name %s is not a suitable machine name.",
+                                               local);
         }
 
         r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTar");
@@ -2197,10 +2188,9 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         remote = argv[1];
-        if (!http_url_is_valid(remote)) {
-                log_error("URL '%s' is not valid.", remote);
-                return -EINVAL;
-        }
+        if (!http_url_is_valid(remote))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "URL '%s' is not valid.", remote);
 
         if (argc >= 3)
                 local = argv[2];
@@ -2221,10 +2211,10 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
 
                 local = ll;
 
-                if (!machine_name_is_valid(local)) {
-                        log_error("Local name %s is not a suitable machine name.", local);
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(local))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Local name %s is not a suitable machine name.",
+                                               local);
         }
 
         r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRaw");
index 22da189684fb3e45d716f04baa326330129623ae..9e570339992fe834496eb45a114026e9c23b7cf1 100644 (file)
@@ -923,10 +923,9 @@ static int umount_by_device(sd_bus *bus, const char *what) {
         if (stat(what, &st) < 0)
                 return log_error_errno(errno, "Can't stat %s: %m", what);
 
-        if (!S_ISBLK(st.st_mode)) {
-                log_error("Not a block device: %s", what);
-                return -ENOTBLK;
-        }
+        if (!S_ISBLK(st.st_mode))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK),
+                                       "Not a block device: %s", what);
 
         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
         if (r < 0)
@@ -1249,10 +1248,10 @@ static int discover_loop_backing_file(void) {
                 escaped = xescape(basename(arg_mount_what), "\\");
                 if (!escaped)
                         return log_oom();
-                if (!filename_is_valid(escaped)) {
-                        log_error("Escaped name %s is not a valid filename.", escaped);
-                        return -EINVAL;
-                }
+                if (!filename_is_valid(escaped))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Escaped name %s is not a valid filename.",
+                                               escaped);
 
                 arg_mount_where = path_join("/run/media/system", escaped);
                 if (!arg_mount_where)
@@ -1265,10 +1264,9 @@ static int discover_loop_backing_file(void) {
         if (stat(loop_dev, &st) < 0)
                 return log_error_errno(errno, "Can't stat %s: %m", loop_dev);
 
-        if (!S_ISBLK(st.st_mode)) {
-                log_error("Invalid file type: %s", loop_dev);
-                return -EINVAL;
-        }
+        if (!S_ISBLK(st.st_mode))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Invalid file type: %s", loop_dev);
 
         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
         if (r < 0)
@@ -1309,19 +1307,19 @@ static int discover_device(void) {
         if (S_ISREG(st.st_mode))
                 return discover_loop_backing_file();
 
-        if (!S_ISBLK(st.st_mode)) {
-                log_error("Invalid file type: %s", arg_mount_what);
-                return -EINVAL;
-        }
+        if (!S_ISBLK(st.st_mode))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Invalid file type: %s",
+                                       arg_mount_what);
 
         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
         if (r < 0)
                 return log_error_errno(r, "Failed to get device from device number: %m");
 
-        if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem")) {
-                log_error("%s does not contain a known file system.", arg_mount_what);
-                return -EINVAL;
-        }
+        if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s does not contain a known file system.",
+                                       arg_mount_what);
 
         r = acquire_mount_type(d);
         if (r < 0)
@@ -1462,10 +1460,10 @@ static int run(int argc, char* argv[]) {
                 return action_umount(bus, argc, argv);
 
         if ((!arg_mount_type || fstype_is_blockdev_backed(arg_mount_type))
-            && !path_is_normalized(arg_mount_what)) {
-                log_error("Path contains non-normalized components: %s", arg_mount_what);
-                return -EINVAL;
-        }
+            && !path_is_normalized(arg_mount_what))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Path contains non-normalized components: %s",
+                                       arg_mount_what);
 
         if (arg_discover) {
                 r = discover_device();
@@ -1473,20 +1471,19 @@ static int run(int argc, char* argv[]) {
                         return r;
         }
 
-        if (!arg_mount_where) {
-                log_error("Can't figure out where to mount %s.", arg_mount_what);
-                return -EINVAL;
-        }
+        if (!arg_mount_where)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Can't figure out where to mount %s.",
+                                       arg_mount_what);
 
-        if (path_equal(arg_mount_where, "/")) {
-                log_error("Refusing to operate on root directory.");
-                return -EINVAL;
-        }
+        if (path_equal(arg_mount_where, "/"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Refusing to operate on root directory.");
 
-        if (!path_is_normalized(arg_mount_where)) {
-                log_error("Path contains non-normalized components: %s", arg_mount_where);
-                return -EINVAL;
-        }
+        if (!path_is_normalized(arg_mount_where))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Path contains non-normalized components: %s",
+                                       arg_mount_where);
 
         if (streq_ptr(arg_mount_type, "auto"))
                 arg_mount_type = mfree(arg_mount_type);
@@ -1516,11 +1513,10 @@ static int run(int argc, char* argv[]) {
         if (arg_mount_type &&
             !streq(arg_mount_type, "auto") &&
             arg_uid != UID_INVALID &&
-            !fstype_can_uid_gid(arg_mount_type)) {
-                log_error("File system type %s is not known to support uid=/gid=, refusing.",
-                          arg_mount_type);
-                return -EOPNOTSUPP;
-        }
+            !fstype_can_uid_gid(arg_mount_type))
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "File system type %s is not known to support uid=/gid=, refusing.",
+                                       arg_mount_type);
 
         switch (arg_action) {
 
index 28941b44682905a2366e002e9f552ec94f163411..c2a197162f2c9931debb3267a9e7310f650ea466 100644 (file)
@@ -111,6 +111,8 @@ sources = files('''
         networkd-speed-meter.h
         networkd-sriov.c
         networkd-sriov.h
+        networkd-sysctl.c
+        networkd-sysctl.h
         networkd-util.c
         networkd-util.h
         networkd-wifi.c
index 9d3b8d6e4cd9b009506cd2448c4cd4fc5aa9f7e8..9f0e6f25c1e51739fc889fd33394b102d48a33b7 100644 (file)
@@ -13,7 +13,6 @@
 #include "memory-util.h"
 #include "netlink-util.h"
 #include "network-internal.h"
-#include "networkd-address.h"
 #include "networkd-manager.h"
 #include "path-util.h"
 #include "socket-util.h"
index 2a3443a6d4e6dcba45ee7926d5546194d3331095..26ad2b7cca9771c848de07267e0c9ca936660c8f 100644 (file)
@@ -4,6 +4,7 @@
 #include <netinet/in.h>
 #include <linux/if_macsec.h>
 
+#include "ether-addr-util.h"
 #include "in-addr-util.h"
 #include "netdev.h"
 #include "networkd-util.h"
index 0c4f93045f430e1b400f2215ae0c76f2b0aca34d..86e53e6da426647b94f4dea6e226a376f20face5 100644 (file)
@@ -1653,12 +1653,11 @@ static int link_status_one(
                 if (r < 0)
                         return table_log_add_error(r);
 
-                if (info->port_state <= BR_STATE_BLOCKING) {
+                if (info->port_state <= BR_STATE_BLOCKING)
                         r = table_add_many(table,
                                            TABLE_EMPTY,
                                            TABLE_STRING, "Port State:",
                                            TABLE_STRING, bridge_state_to_string(info->port_state));
-                }
         } else if (streq_ptr(info->netdev_kind, "bond")) {
                 r = table_add_many(table,
                                    TABLE_EMPTY,
index 0d53aa90429b333d7ebaa232160498130f2df03a..66b192256e98373735b99150786c995a8fe3b53c 100644 (file)
@@ -4,31 +4,28 @@
 #include <linux/if_addrlabel.h>
 
 #include "alloc-util.h"
-#include "conf-parser.h"
-#include "networkd-address-label.h"
 #include "netlink-util.h"
+#include "networkd-address-label.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
+#include "networkd-network.h"
 #include "parse-util.h"
-#include "socket-util.h"
 
-void address_label_free(AddressLabel *label) {
+AddressLabel *address_label_free(AddressLabel *label) {
         if (!label)
-                return;
+                return NULL;
 
         if (label->network) {
-                LIST_REMOVE(labels, label->network->address_labels, label);
-                assert(label->network->n_address_labels > 0);
-                label->network->n_address_labels--;
-
-                if (label->section) {
-                        hashmap_remove(label->network->address_labels_by_section, label->section);
-                        network_config_section_free(label->section);
-                }
+                assert(label->section);
+                hashmap_remove(label->network->address_labels_by_section, label->section);
         }
 
-        free(label);
+        network_config_section_free(label->section);
+        return mfree(label);
 }
 
+DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
+
 static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(address_label_freep) AddressLabel *label = NULL;
@@ -36,19 +33,17 @@ static int address_label_new_static(Network *network, const char *filename, unsi
 
         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;
+        assert(filename);
+        assert(section_line > 0);
 
-                label = hashmap_get(network->address_labels_by_section, n);
-                if (label) {
-                        *ret = TAKE_PTR(label);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        label = hashmap_get(network->address_labels_by_section, n);
+        if (label) {
+                *ret = TAKE_PTR(label);
+                return 0;
         }
 
         label = new(AddressLabel, 1);
@@ -57,25 +52,18 @@ static int address_label_new_static(Network *network, const char *filename, unsi
 
         *label = (AddressLabel) {
                 .network = network,
+                .section = TAKE_PTR(n),
         };
 
-        LIST_APPEND(labels, network->address_labels, label);
-        network->n_address_labels++;
-
-        if (filename) {
-                label->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->address_labels_by_section, label->section, label);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->address_labels_by_section, label->section, label);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(label);
-
         return 0;
 }
 
@@ -107,12 +95,7 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
         return 1;
 }
 
-int address_label_configure(
-                AddressLabel *label,
-                Link *link,
-                link_netlink_message_handler_t callback,
-                bool update) {
-
+static int address_label_configure(AddressLabel *label, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -140,7 +123,7 @@ int address_label_configure(
                 return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req,
-                               callback ?: address_label_handler,
+                               address_label_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -150,6 +133,34 @@ int address_label_configure(
         return 0;
 }
 
+int link_set_address_labels(Link *link) {
+        AddressLabel *label;
+        int r;
+
+        assert(link);
+        assert(link->network);
+
+        HASHMAP_FOREACH(label, link->network->address_labels_by_section) {
+                r = address_label_configure(label, link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not set address label: %m");
+
+                link->address_label_messages++;
+        }
+
+        return 0;
+}
+
+void network_drop_invalid_address_labels(Network *network) {
+        AddressLabel *label;
+
+        assert(network);
+
+        HASHMAP_FOREACH(label, network->address_labels_by_section)
+                if (section_is_invalid(label->section))
+                        address_label_free(label);
+}
+
 int config_parse_address_label_prefix(const char *unit,
                                       const char *filename,
                                       unsigned line,
index 595072a17e6fc5992e9076e1e6536b319becd951..b92828c72e25084d14cf95cb7e2da98cdcdda7c7 100644 (file)
@@ -2,38 +2,28 @@
 #pragma once
 
 #include <inttypes.h>
-#include <stdbool.h>
 
 #include "conf-parser.h"
 #include "in-addr-util.h"
-
-typedef struct AddressLabel AddressLabel;
-
-#include "networkd-link.h"
-#include "networkd-network.h"
 #include "networkd-util.h"
 
 typedef struct Network Network;
 typedef struct Link Link;
-typedef struct NetworkConfigSection NetworkConfigSection;
 
-struct AddressLabel {
+typedef struct AddressLabel {
         Network *network;
         NetworkConfigSection *section;
 
         unsigned char prefixlen;
         uint32_t label;
-
         union in_addr_union in_addr;
+} AddressLabel;
 
-        LIST_FIELDS(AddressLabel, labels);
-};
-
-void address_label_free(AddressLabel *label);
+AddressLabel *address_label_free(AddressLabel *label);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
+void network_drop_invalid_address_labels(Network *network);
 
-int address_label_configure(AddressLabel *address, Link *link, link_netlink_message_handler_t callback, bool update);
+int link_set_address_labels(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_address_label);
 CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix);
index b4a94f0728271cf613265475a0b8c7ae59610f67..c732b6c56e44d4817e3a3914cb666b73ad2a9e21 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "alloc-util.h"
 #include "networkd-address-pool.h"
+#include "networkd-address.h"
 #include "networkd-manager.h"
 #include "set.h"
 #include "string-util.h"
 
 static int address_pool_new(
                 Manager *m,
-                AddressPool **ret,
                 int family,
                 const union in_addr_union *u,
                 unsigned prefixlen) {
 
-        AddressPool *p;
+        _cleanup_free_ AddressPool *p = NULL;
+        int r;
 
         assert(m);
-        assert(ret);
         assert(u);
 
         p = new(AddressPool, 1);
@@ -32,15 +32,16 @@ static int address_pool_new(
                 .in_addr = *u,
         };
 
-        LIST_PREPEND(address_pools, m->address_pools, p);
+        r = ordered_set_ensure_put(&m->address_pools, NULL, p);
+        if (r < 0)
+                return r;
 
-        *ret = p;
+        TAKE_PTR(p);
         return 0;
 }
 
-int address_pool_new_from_string(
+static int address_pool_new_from_string(
                 Manager *m,
-                AddressPool **ret,
                 int family,
                 const char *p,
                 unsigned prefixlen) {
@@ -49,25 +50,38 @@ int address_pool_new_from_string(
         int r;
 
         assert(m);
-        assert(ret);
         assert(p);
 
         r = in_addr_from_string(family, p, &u);
         if (r < 0)
                 return r;
 
-        return address_pool_new(m, ret, family, &u, prefixlen);
+        return address_pool_new(m, family, &u, prefixlen);
 }
 
-void address_pool_free(AddressPool *p) {
+int address_pool_setup_default(Manager *m) {
+        int r;
 
-        if (!p)
-                return;
+        assert(m);
 
-        if (p->manager)
-                LIST_REMOVE(address_pools, p->manager->address_pools, p);
+        /* Add in the well-known private address ranges. */
+        r = address_pool_new_from_string(m, AF_INET6, "fd00::", 8);
+        if (r < 0)
+                return r;
+
+        r = address_pool_new_from_string(m, AF_INET, "192.168.0.0", 16);
+        if (r < 0)
+                return r;
+
+        r = address_pool_new_from_string(m, AF_INET, "172.16.0.0", 12);
+        if (r < 0)
+                return r;
+
+        r = address_pool_new_from_string(m, AF_INET, "10.0.0.0", 8);
+        if (r < 0)
+                return r;
 
-        free(p);
+        return 0;
 }
 
 static bool address_pool_prefix_is_taken(
@@ -94,7 +108,7 @@ static bool address_pool_prefix_is_taken(
                 }
 
                 /* Don't clash with addresses already pulled from the pool, but not assigned yet */
-                LIST_FOREACH(addresses, a, l->pool_addresses) {
+                SET_FOREACH(a, l->pool_addresses) {
                         if (a->family != p->family)
                                 continue;
 
@@ -107,7 +121,7 @@ static bool address_pool_prefix_is_taken(
         ORDERED_HASHMAP_FOREACH(n, p->manager->networks) {
                 Address *a;
 
-                LIST_FOREACH(addresses, a, n->static_addresses) {
+                ORDERED_HASHMAP_FOREACH(a, n->addresses_by_section) {
                         if (a->family != p->family)
                                 continue;
 
@@ -119,7 +133,7 @@ static bool address_pool_prefix_is_taken(
         return false;
 }
 
-int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
+static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixlen, union in_addr_union *found) {
         union in_addr_union u;
         unsigned i;
         int r;
@@ -128,6 +142,9 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
         assert(prefixlen > 0);
         assert(found);
 
+        if (p->family != family)
+                return 0;
+
         if (p->prefixlen >= prefixlen)
                 return 0;
 
@@ -153,3 +170,21 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
 
         return 0;
 }
+
+int address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
+        AddressPool *p;
+        int r;
+
+        assert(m);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(prefixlen > 0);
+        assert(found);
+
+        ORDERED_SET_FOREACH(p, m->address_pools) {
+                r = address_pool_acquire_one(p, family, prefixlen, found);
+                if (r != 0)
+                        return r;
+        }
+
+        return 0;
+}
index 7db1c4f26c17f6fee24a82b0c583ca25de107ef7..c53fe7407febbd3438444b985f2d840a1fc57aae 100644 (file)
@@ -1,25 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-typedef struct AddressPool AddressPool;
-
 #include "in-addr-util.h"
-#include "list.h"
 
 typedef struct Manager Manager;
 
-struct AddressPool {
+typedef struct AddressPool {
         Manager *manager;
 
         int family;
         unsigned prefixlen;
-
         union in_addr_union in_addr;
+} AddressPool;
 
-        LIST_FIELDS(AddressPool, address_pools);
-};
-
-int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen);
-void address_pool_free(AddressPool *p);
-
-int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found);
+int address_pool_setup_default(Manager *m);
+int address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);
index 76c91ef9dd2f2fb1b4d15ff5be47715e5a3d3956..9130fae77830f32bc60a763cc6034d7d60b1c16c 100644 (file)
@@ -3,25 +3,21 @@
 #include <net/if.h>
 
 #include "alloc-util.h"
-#include "conf-parser.h"
 #include "firewall-util.h"
 #include "memory-util.h"
-#include "missing_network.h"
 #include "netlink-util.h"
+#include "networkd-address-pool.h"
 #include "networkd-address.h"
 #include "networkd-manager.h"
-#include "networkd-ndisc.h"
+#include "networkd-network.h"
 #include "parse-util.h"
-#include "set.h"
-#include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "utf8.h"
 
 #define ADDRESSES_PER_LINK_MAX 2048U
 #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
 
-int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) {
+int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret) {
         assert(link);
         assert(ret);
 
@@ -52,7 +48,6 @@ int address_new(Address **ret) {
                 .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME,
                 .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME,
                 .duplicate_address_detection = ADDRESS_FAMILY_IPV6,
-                .prefix_route = true,
         };
 
         *ret = TAKE_PTR(address);
@@ -67,22 +62,20 @@ static int address_new_static(Network *network, const char *filename, unsigned s
 
         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;
+        assert(filename);
+        assert(section_line > 0);
 
-                address = hashmap_get(network->addresses_by_section, n);
-                if (address) {
-                        *ret = TAKE_PTR(address);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        address = ordered_hashmap_get(network->addresses_by_section, n);
+        if (address) {
+                *ret = TAKE_PTR(address);
+                return 0;
         }
 
-        if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
+        if (ordered_hashmap_size(network->addresses_by_section) >= STATIC_ADDRESSES_PER_NETWORK_MAX)
                 return -E2BIG;
 
         r = address_new(&address);
@@ -90,40 +83,30 @@ static int address_new_static(Network *network, const char *filename, unsigned s
                 return r;
 
         address->network = network;
-        LIST_APPEND(addresses, network->static_addresses, address);
-        network->n_static_addresses++;
+        address->section = TAKE_PTR(n);
 
-        if (filename) {
-                address->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = ordered_hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->addresses_by_section, address->section, address);
-                if (r < 0)
-                        return r;
-        }
+        r = ordered_hashmap_put(network->addresses_by_section, address->section, address);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(address);
-
         return 0;
 }
 
-void address_free(Address *address) {
+Address *address_free(Address *address) {
         if (!address)
-                return;
+                return NULL;
 
         if (address->network) {
-                LIST_REMOVE(addresses, address->network->static_addresses, address);
-                assert(address->network->n_static_addresses > 0);
-                address->network->n_static_addresses--;
-
-                if (address->section)
-                        hashmap_remove(address->network->addresses_by_section, address->section);
+                assert(address->section);
+                ordered_hashmap_remove(address->network->addresses_by_section, address->section);
         }
 
-        if (address->link && !address->acd) {
+        if (address->link) {
                 NDiscAddress *n;
 
                 set_remove(address->link->addresses, address);
@@ -149,21 +132,7 @@ void address_free(Address *address) {
 
         network_config_section_free(address->section);
         free(address->label);
-        free(address);
-}
-
-static uint32_t address_prefix(const Address *a) {
-        assert(a);
-
-        /* make sure we don't try to shift by 32.
-         * See ISO/IEC 9899:TC3 § 6.5.7.3. */
-        if (a->prefixlen == 0)
-                return 0;
-
-        if (a->in_addr_peer.in.s_addr != 0)
-                return be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
-        else
-                return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
+        return mfree(address);
 }
 
 void address_hash_func(const Address *a, struct siphash *state) {
@@ -173,16 +142,16 @@ void address_hash_func(const Address *a, struct siphash *state) {
 
         switch (a->family) {
         case AF_INET:
-                siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
-
-                /* peer prefix */
-                uint32_t prefix = address_prefix(a);
-                siphash24_compress(&prefix, sizeof(prefix), state);
+                siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
+                siphash24_compress_string(a->label, state);
 
                 _fallthrough_;
         case AF_INET6:
+                siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
                 /* local address */
                 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+                /* peer address */
+                siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
 
                 break;
         default:
@@ -201,19 +170,25 @@ int address_compare_func(const Address *a1, const Address *a2) {
         switch (a1->family) {
         /* use the same notion of equality as the kernel does */
         case AF_INET:
-                r = CMP(a1->prefixlen, a2->prefixlen);
+                r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
                 if (r != 0)
                         return r;
 
-                uint32_t prefix1 = address_prefix(a1);
-                uint32_t prefix2 = address_prefix(a2);
-                r = CMP(prefix1, prefix2);
+                r = strcmp_ptr(a1->label, a2->label);
                 if (r != 0)
                         return r;
 
                 _fallthrough_;
         case AF_INET6:
-                return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+                r = CMP(a1->prefixlen, a2->prefixlen);
+                if (r != 0)
+                        return r;
+
+                r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+                if (r != 0)
+                        return r;
+
+                return memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
         default:
                 /* treat any other address family as AF_UNSPEC */
                 return 0;
@@ -222,7 +197,7 @@ int address_compare_func(const Address *a1, const Address *a2) {
 
 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
 
-bool address_equal(Address *a1, Address *a2) {
+bool address_equal(const Address *a1, const Address *a2) {
         if (a1 == a2)
                 return true;
 
@@ -232,52 +207,81 @@ bool address_equal(Address *a1, Address *a2) {
         return address_compare_func(a1, a2) == 0;
 }
 
-static int address_establish(Address *address, Link *link) {
-        bool masq;
+static int address_copy(Address *dest, const Address *src) {
+        int r;
+
+        assert(dest);
+        assert(src);
+
+        r = free_and_strdup(&dest->label, src->label);
+        if (r < 0)
+                return r;
+
+        dest->family = src->family;
+        dest->prefixlen = src->prefixlen;
+        dest->scope = src->scope;
+        dest->flags = src->flags;
+        dest->broadcast = src->broadcast;
+        dest->cinfo = src->cinfo;
+        dest->in_addr = src->in_addr;
+        dest->in_addr_peer = src->in_addr_peer;
+        dest->duplicate_address_detection = src->duplicate_address_detection;
+
+        return 0;
+}
+
+static int address_set_masquerade(Address *address, bool add) {
+        union in_addr_union masked;
         int r;
 
         assert(address);
-        assert(link);
+        assert(address->link);
+
+        if (!address->link->network)
+                return 0;
 
-        masq = link->network &&
-               link->network->ip_masquerade &&
-               address->family == AF_INET &&
-               address->scope < RT_SCOPE_LINK;
+        if (!address->link->network->ip_masquerade)
+                return 0;
 
-        /* Add firewall entry if this is requested */
-        if (address->ip_masquerade_done != masq) {
-                union in_addr_union masked = address->in_addr;
-                in_addr_mask(address->family, &masked, address->prefixlen);
+        if (address->family != AF_INET)
+                return 0;
 
-                r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
-                if (r < 0)
-                        return r;
+        if (address->scope >= RT_SCOPE_LINK)
+                return 0;
 
-                address->ip_masquerade_done = masq;
-        }
+        if (address->ip_masquerade_done == add)
+                return 0;
+
+        masked = address->in_addr;
+        r = in_addr_mask(address->family, &masked, address->prefixlen);
+        if (r < 0)
+                return r;
+
+        r = fw_add_masquerade(add, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
+        if (r < 0)
+                return r;
+
+        address->ip_masquerade_done = add;
 
         return 0;
 }
 
-static int address_add_internal(Link *link, Set **addresses,
-                                int family,
-                                const union in_addr_union *in_addr,
-                                unsigned char prefixlen,
-                                Address **ret) {
+static int address_add_internal(Link *link, Set **addresses, const Address *in, Address **ret) {
         _cleanup_(address_freep) Address *address = NULL;
         int r;
 
         assert(link);
         assert(addresses);
-        assert(in_addr);
+        assert(in);
 
         r = address_new(&address);
         if (r < 0)
                 return r;
 
-        address->family = family;
-        address->in_addr = *in_addr;
-        address->prefixlen = prefixlen;
+        r = address_copy(address, in);
+        if (r < 0)
+                return r;
+
         /* Consider address tentative until we get the real flags from the kernel */
         address->flags = IFA_F_TENTATIVE;
 
@@ -295,18 +299,21 @@ static int address_add_internal(Link *link, Set **addresses,
         return 0;
 }
 
-int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
-        return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
+static int address_add_foreign(Link *link, const Address *in, Address **ret) {
+        return address_add_internal(link, &link->addresses_foreign, in, ret);
 }
 
-int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+static int address_add(Link *link, const Address *in, Address **ret) {
         Address *address;
         int r;
 
-        r = address_get(link, family, in_addr, prefixlen, &address);
+        assert(link);
+        assert(in);
+
+        r = address_get(link, in, &address);
         if (r == -ENOENT) {
                 /* Address does not exist, create a new one */
-                r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
+                r = address_add_internal(link, &link->addresses, in, &address);
                 if (r < 0)
                         return r;
         } else if (r == 0) {
@@ -328,45 +335,19 @@ int address_add(Link *link, int family, const union in_addr_union *in_addr, unsi
         return 0;
 }
 
-static int address_release(Address *address) {
-        int r;
-
-        assert(address);
-        assert(address->link);
-
-        /* Remove masquerading firewall entry if it was added */
-        if (address->ip_masquerade_done) {
-                union in_addr_union masked = address->in_addr;
-                in_addr_mask(address->family, &masked, address->prefixlen);
-
-                r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
-                if (r < 0)
-                        return r;
-
-                address->ip_masquerade_done = false;
-        }
-
-        return 0;
-}
-
-int address_update(
-                Address *address,
-                unsigned char flags,
-                unsigned char scope,
-                const struct ifa_cacheinfo *cinfo) {
-
+static int address_update(Address *address, const Address *src) {
         bool ready;
         int r;
 
         assert(address);
         assert(address->link);
-        assert(cinfo);
+        assert(src);
 
         ready = address_is_ready(address);
 
-        address->flags = flags;
-        address->scope = scope;
-        address->cinfo = *cinfo;
+        address->flags = src->flags;
+        address->scope = src->scope;
+        address->cinfo = src->cinfo;
 
         if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 0;
@@ -394,7 +375,7 @@ int address_update(
         return 0;
 }
 
-int address_drop(Address *address) {
+static int address_drop(Address *address) {
         Link *link;
         bool ready;
         int r;
@@ -404,7 +385,7 @@ int address_drop(Address *address) {
         ready = address_is_ready(address);
         link = address->link;
 
-        r = address_release(address);
+        r = address_set_masquerade(address, false);
         if (r < 0)
                 log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
 
@@ -418,31 +399,20 @@ int address_drop(Address *address) {
         return 0;
 }
 
-int address_get(Link *link,
-                int family,
-                const union in_addr_union *in_addr,
-                unsigned char prefixlen,
-                Address **ret) {
-
-        Address address, *existing;
+int address_get(Link *link, const Address *in, Address **ret) {
+        Address *existing;
 
         assert(link);
-        assert(in_addr);
-
-        address = (Address) {
-                .family = family,
-                .in_addr = *in_addr,
-                .prefixlen = prefixlen,
-        };
+        assert(in);
 
-        existing = set_get(link->addresses, &address);
+        existing = set_get(link->addresses, in);
         if (existing) {
                 if (ret)
                         *ret = existing;
                 return 1;
         }
 
-        existing = set_get(link->addresses_foreign, &address);
+        existing = set_get(link->addresses_foreign, in);
         if (existing) {
                 if (ret)
                         *ret = existing;
@@ -497,7 +467,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
 }
 
 int address_remove(
-                Address *address,
+                const Address *address,
                 Link *link,
                 link_netlink_message_handler_t callback) {
 
@@ -542,7 +512,189 @@ int address_remove(
         return 0;
 }
 
-static int address_acquire(Link *link, Address *original, Address **ret) {
+static bool link_is_static_address_configured(const Link *link, const Address *address) {
+        Address *net_address;
+
+        assert(link);
+        assert(address);
+
+        if (!link->network)
+                return false;
+
+        ORDERED_HASHMAP_FOREACH(net_address, link->network->addresses_by_section)
+                if (address_equal(net_address, address))
+                        return true;
+
+        return false;
+}
+
+static bool link_address_is_dynamic(const Link *link, const Address *address) {
+        Route *route;
+
+        assert(link);
+        assert(address);
+
+        if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
+                return true;
+
+        /* Even when the address is leased from a DHCP server, networkd assign the address
+         * without lifetime when KeepConfiguration=dhcp. So, let's check that we have
+         * corresponding routes with RTPROT_DHCP. */
+        SET_FOREACH(route, link->routes_foreign) {
+                if (route->protocol != RTPROT_DHCP)
+                        continue;
+
+                if (address->family != route->family)
+                        continue;
+
+                if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
+                        return true;
+        }
+
+        return false;
+}
+
+static int link_enumerate_ipv6_tentative_addresses(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *addr;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+
+        r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, 0, AF_INET6);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(link->manager->rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
+                unsigned char flags;
+                int ifindex;
+
+                r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: invalid ifindex, ignoring: %m");
+                        continue;
+                } else if (link->ifindex != ifindex)
+                        continue;
+
+                r = sd_rtnl_message_addr_get_flags(addr, &flags);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
+                        continue;
+                } else if (!(flags & IFA_F_TENTATIVE))
+                        continue;
+
+                log_link_debug(link, "Found tentative ipv6 link-local address");
+                (void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager);
+        }
+
+        return 0;
+}
+
+int link_drop_foreign_addresses(Link *link) {
+        Address *address;
+        int k, r = 0;
+
+        assert(link);
+
+        /* The kernel doesn't notify us about tentative addresses;
+         * so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */
+        if (!link_ipv6ll_enabled(link)) {
+                r = link_enumerate_ipv6_tentative_addresses(link);
+                if (r < 0)
+                        return r;
+        }
+
+        SET_FOREACH(address, link->addresses_foreign) {
+                /* we consider IPv6LL addresses to be managed by the kernel */
+                if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
+                        continue;
+
+                if (link_address_is_dynamic(link, address)) {
+                        if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+                                continue;
+                } else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+                        continue;
+
+                if (link_is_static_address_configured(link, address)) {
+                        k = address_add(link, address, NULL);
+                        if (k < 0) {
+                                log_link_error_errno(link, k, "Failed to add address: %m");
+                                if (r >= 0)
+                                        r = k;
+                        }
+                } else {
+                        k = address_remove(address, link, NULL);
+                        if (k < 0 && r >= 0)
+                                r = k;
+                }
+        }
+
+        return r;
+}
+
+static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->address_remove_messages > 0);
+
+        link->address_remove_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 != -EADDRNOTAVAIL)
+                log_link_message_warning_errno(link, m, r, "Could not drop address");
+        else if (r >= 0)
+                (void) manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->address_remove_messages == 0 && link->request_static_addresses) {
+                link_set_state(link, LINK_STATE_CONFIGURING);
+                r = link_set_addresses(link);
+                if (r < 0)
+                        link_enter_failed(link);
+        }
+
+        return 1;
+}
+
+int link_drop_addresses(Link *link) {
+        Address *address, *pool_address;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(address, link->addresses) {
+                /* we consider IPv6LL addresses to be managed by the kernel */
+                if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
+                        continue;
+
+                k = address_remove(address, link, remove_static_address_handler);
+                if (k < 0 && r >= 0) {
+                        r = k;
+                        continue;
+                }
+
+                link->address_remove_messages++;
+
+                SET_FOREACH(pool_address, link->pool_addresses)
+                        if (address_equal(address, pool_address))
+                                address_free(set_remove(link->pool_addresses, pool_address));
+        }
+
+        return r;
+}
+
+static int address_acquire(Link *link, const Address *original, Address **ret) {
         union in_addr_union in_addr = IN_ADDR_NULL;
         struct in_addr broadcast = {};
         _cleanup_(address_freep) Address *na = NULL;
@@ -554,12 +706,16 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
 
         /* Something useful was configured? just use it */
         r = in_addr_is_null(original->family, &original->in_addr);
-        if (r <= 0)
+        if (r < 0)
                 return r;
+        if (r == 0) {
+                *ret = NULL;
+                return 0;
+        }
 
         /* The address is configured to be 0.0.0.0 or [::] by the user?
          * Then let's acquire something more useful from the pool. */
-        r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
+        r = address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
         if (r < 0)
                 return r;
         if (r == 0)
@@ -581,36 +737,35 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
         if (r < 0)
                 return r;
 
-        na->family = original->family;
-        na->prefixlen = original->prefixlen;
-        na->scope = original->scope;
-        na->cinfo = original->cinfo;
-
-        if (original->label) {
-                na->label = strdup(original->label);
-                if (!na->label)
-                        return -ENOMEM;
-        }
+        r = address_copy(na, original);
+        if (r < 0)
+                return r;
 
         na->broadcast = broadcast;
         na->in_addr = in_addr;
 
-        LIST_PREPEND(addresses, link->pool_addresses, na);
+        r = set_ensure_put(&link->pool_addresses, &address_hash_ops, na);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EEXIST;
 
         *ret = TAKE_PTR(na);
-
-        return 0;
+        return 1;
 }
 
+static int ipv4_dad_configure(Address *address);
+
 int address_configure(
-                Address *address,
+                const Address *address,
                 Link *link,
                 link_netlink_message_handler_t callback,
                 bool update,
                 Address **ret) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        Address *a;
+        Address *acquired_address, *a;
+        uint32_t flags;
         int r;
 
         assert(address);
@@ -622,14 +777,16 @@ int address_configure(
         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 &&
+        if (address_get(link, address, NULL) <= 0 &&
             set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
                 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
                                             "Too many addresses are configured, refusing: %m");
 
-        r = address_acquire(link, address, &address);
+        r = address_acquire(link, address, &acquired_address);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
+        if (acquired_address)
+                address = acquired_address;
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *str = NULL;
@@ -651,29 +808,13 @@ int address_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set prefixlen: %m");
 
-        address->flags |= IFA_F_PERMANENT;
-
-        if (address->home_address)
-                address->flags |= IFA_F_HOMEADDRESS;
-
-        if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6))
-                address->flags |= IFA_F_NODAD;
-
-        if (address->manage_temporary_address)
-                address->flags |= IFA_F_MANAGETEMPADDR;
-
-        if (!address->prefix_route)
-                address->flags |= IFA_F_NOPREFIXROUTE;
-
-        if (address->autojoin)
-                address->flags |= IFA_F_MCAUTOJOIN;
-
-        r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
+        flags = address->flags | IFA_F_PERMANENT;
+        r = sd_rtnl_message_addr_set_flags(req, flags & 0xff);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set flags: %m");
 
-        if (address->flags & ~0xff) {
-                r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
+        if (flags & ~0xff) {
+                r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set extended flags: %m");
         }
@@ -706,37 +847,24 @@ int address_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
 
-        r = address_establish(address, link);
+        r = address_add(link, address, &a);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not add address: %m");
+
+        r = address_set_masquerade(a, true);
         if (r < 0)
                 log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link);
         if (r < 0) {
-                address_release(address);
+                (void) address_set_masquerade(a, false);
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
         }
 
         link_ref(link);
 
-        if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
-                r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
-        else
-                r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
-        if (r < 0) {
-                address_release(address);
-                return log_link_error_errno(link, r, "Could not add address: %m");
-        }
-
-        if (address->acd) {
-                assert(address->family == AF_INET);
-                if (DEBUG_LOGGING) {
-                        _cleanup_free_ char *pretty = NULL;
-
-                        (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
-                        log_link_debug(link, "Starting IPv4ACD client. Probing address %s", strna(pretty));
-                }
-
-                r = sd_ipv4acd_start(address->acd, true);
+        if (FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
+                r = ipv4_dad_configure(a);
                 if (r < 0)
                         log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
         }
@@ -747,27 +875,454 @@ int address_configure(
         return 1;
 }
 
-static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
-        _cleanup_free_ char *pretty = NULL;
-        Address *address;
+static int static_address_ready_callback(Address *address) {
+        Address *a;
         Link *link;
-        int r;
 
-        assert(acd);
-        assert(userdata);
+        assert(address);
+        assert(address->link);
 
-        address = (Address *) userdata;
         link = address->link;
 
-        (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
-        switch (event) {
-        case SD_IPV4ACD_EVENT_STOP:
-                log_link_debug(link, "Stopping ACD client...");
-                return;
+        if (!link->addresses_configured)
+                return 0;
 
-        case SD_IPV4ACD_EVENT_BIND:
-                log_link_debug(link, "Successfully claimed address %s", strna(pretty));
-                link_check_ready(link);
+        SET_FOREACH(a, link->static_addresses)
+                if (!address_is_ready(a)) {
+                        _cleanup_free_ char *str = NULL;
+
+                        (void) in_addr_to_string(a->family, &a->in_addr, &str);
+                        log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
+                        return 0;
+                }
+
+        /* This should not be called again */
+        SET_FOREACH(a, link->static_addresses)
+                a->callback = NULL;
+
+        link->addresses_ready = true;
+
+        return link_set_routes(link);
+}
+
+static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(rtnl);
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->address_messages > 0);
+        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
+               LINK_STATE_FAILED, LINK_STATE_LINGER));
+
+        link->address_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_message_warning_errno(link, m, r, "Could not set address");
+                link_enter_failed(link);
+                return 1;
+        } else if (r >= 0)
+                (void) manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->address_messages == 0) {
+                Address *a;
+
+                log_link_debug(link, "Addresses set");
+                link->addresses_configured = true;
+
+                /* When all static addresses are already ready, then static_address_ready_callback()
+                 * will not be called automatically. So, call it here. */
+                a = set_first(link->static_addresses);
+                if (!a) {
+                        log_link_warning(link, "No static address is stored.");
+                        link_enter_failed(link);
+                        return 1;
+                }
+                if (!a->callback) {
+                        log_link_warning(link, "Address ready callback is not set.");
+                        link_enter_failed(link);
+                        return 1;
+                }
+                r = a->callback(a);
+                if (r < 0)
+                        link_enter_failed(link);
+        }
+
+        return 1;
+}
+
+static int static_address_configure(const Address *address, Link *link, bool update) {
+        Address *ret;
+        int r;
+
+        assert(address);
+        assert(link);
+
+        r = address_configure(address, link, address_handler, update, &ret);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Could not configure static address: %m");
+
+        link->address_messages++;
+
+        r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to store static address: %m");
+
+        ret->callback = static_address_ready_callback;
+
+        return 0;
+}
+
+int link_set_addresses(Link *link) {
+        Address *ad;
+        Prefix *p;
+        int r;
+
+        assert(link);
+        assert(link->network);
+
+        if (link->address_remove_messages != 0) {
+                log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
+                link->request_static_addresses = true;
+                return 0;
+        }
+
+        ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) {
+                bool update;
+
+                update = address_get(link, ad, NULL) > 0;
+                r = static_address_configure(ad, link, update);
+                if (r < 0)
+                        return r;
+        }
+
+        HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
+                _cleanup_(address_freep) Address *address = NULL;
+
+                if (!p->assign)
+                        continue;
+
+                r = address_new(&address);
+                if (r < 0)
+                        return log_oom();
+
+                r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
+
+                r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
+
+                address->family = AF_INET6;
+                r = static_address_configure(address, link, true);
+                if (r < 0)
+                        return r;
+        }
+
+        if (link->address_messages == 0) {
+                link->addresses_configured = true;
+                link->addresses_ready = true;
+                r = link_set_routes(link);
+                if (r < 0)
+                        return r;
+        } else {
+                log_link_debug(link, "Setting addresses");
+                link_set_state(link, LINK_STATE_CONFIGURING);
+        }
+
+        return 0;
+}
+
+int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
+        _cleanup_(address_freep) Address *tmp = NULL;
+        _cleanup_free_ char *buf = NULL, *buf_peer = NULL;
+        Link *link = NULL;
+        uint16_t type;
+        unsigned char flags;
+        Address *address = NULL;
+        char valid_buf[FORMAT_TIMESPAN_MAX];
+        const char *valid_str = NULL;
+        int ifindex, r;
+        bool has_peer = false;
+
+        assert(rtnl);
+        assert(message);
+        assert(m);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_message_warning_errno(message, r, "rtnl: failed to receive address message, ignoring");
+
+                return 0;
+        }
+
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
+                log_warning("rtnl: received unexpected message type %u when processing address, ignoring.", type);
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
+                return 0;
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received address message with invalid ifindex %d, ignoring.", ifindex);
+                return 0;
+        }
+
+        r = link_get(m, ifindex, &link);
+        if (r < 0 || !link) {
+                /* when enumerating we might be out of sync, but we will get the address again, so just
+                 * ignore it */
+                if (!m->enumerating)
+                        log_warning("rtnl: received address for link '%d' we don't know about, ignoring.", ifindex);
+                return 0;
+        }
+
+        r = address_new(&tmp);
+        if (r < 0)
+                return log_oom();
+
+        r = sd_rtnl_message_addr_get_family(message, &tmp->family);
+        if (r < 0) {
+                log_link_warning(link, "rtnl: received address message without family, ignoring.");
+                return 0;
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", tmp->family);
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_prefixlen(message, &tmp->prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address message without prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_scope(message, &tmp->scope);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address message without scope, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_flags(message, &flags);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address message without flags, ignoring: %m");
+                return 0;
+        }
+        tmp->flags = flags;
+
+        switch (tmp->family) {
+        case AF_INET:
+                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &tmp->in_addr.in);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        if (in4_addr_equal(&tmp->in_addr.in, &tmp->in_addr_peer.in))
+                                tmp->in_addr_peer = IN_ADDR_NULL;
+                        else
+                                has_peer = true;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &tmp->broadcast);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get broadcast from address message, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_string_strdup(message, IFA_LABEL, &tmp->label);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get label from address message, ignoring: %m");
+                        return 0;
+                } else if (r >= 0 && streq_ptr(tmp->label, link->ifname))
+                        tmp->label = mfree(tmp->label);
+
+                break;
+
+        case AF_INET6:
+                r = sd_netlink_message_read_in6_addr(message, IFA_LOCAL, &tmp->in_addr.in6);
+                if (r >= 0) {
+                        /* Have peer address. */
+                        r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in6);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
+                                return 0;
+                        }
+                        has_peer = true;
+                } else if (r == -ENODATA) {
+                        /* Does not have peer address. */
+                        r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr.in6);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
+                                return 0;
+                        }
+                } else {
+                        log_link_warning_errno(link, r, "rtnl: could not get local address from address message, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        default:
+                assert_not_reached("Received unsupported address family");
+        }
+
+        (void) in_addr_to_string(tmp->family, &tmp->in_addr, &buf);
+        (void) in_addr_to_string(tmp->family, &tmp->in_addr_peer, &buf_peer);
+
+        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
+                return 0;
+        } else if (r >= 0 && tmp->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
+                valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+                                            tmp->cinfo.ifa_valid * USEC_PER_SEC,
+                                            USEC_PER_SEC);
+
+        (void) address_get(link, tmp, &address);
+
+        switch (type) {
+        case RTM_NEWADDR:
+                if (address)
+                        log_link_debug(link, "Remembering updated address: %s%s%s/%u (valid %s%s)",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
+                                       valid_str ? "for " : "forever", strempty(valid_str));
+                else {
+                        /* An address appeared that we did not request */
+                        r = address_add_foreign(link, tmp, &address);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m",
+                                                       strnull(buf), tmp->prefixlen);
+                                return 0;
+                        } else
+                                log_link_debug(link, "Remembering foreign address: %s%s%s/%u (valid %s%s)",
+                                               strnull(buf), has_peer ? " peer " : "",
+                                               has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
+                                               valid_str ? "for " : "forever", strempty(valid_str));
+                }
+
+                /* address_update() logs internally, so we don't need to here. */
+                r = address_update(address, tmp);
+                if (r < 0)
+                        link_enter_failed(link);
+
+                break;
+
+        case RTM_DELADDR:
+                if (address) {
+                        log_link_debug(link, "Forgetting address: %s%s%s/%u (valid %s%s)",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
+                                       valid_str ? "for " : "forever", strempty(valid_str));
+                        (void) address_drop(address);
+                } else
+                        log_link_debug(link, "Kernel removed an address we don't remember: %s%s%s/%u (valid %s%s), ignoring.",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
+                                       valid_str ? "for " : "forever", strempty(valid_str));
+
+                break;
+
+        default:
+                assert_not_reached("Received invalid RTNL message type");
+        }
+
+        return 1;
+}
+
+int link_serialize_addresses(Link *link, FILE *f) {
+        bool space = false;
+        Address *a;
+
+        assert(link);
+
+        fputs("ADDRESSES=", f);
+        SET_FOREACH(a, link->addresses) {
+                _cleanup_free_ char *address_str = NULL;
+
+                if (in_addr_to_string(a->family, &a->in_addr, &address_str) < 0)
+                        continue;
+
+                fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
+                space = true;
+        }
+        fputc('\n', f);
+
+        return 0;
+}
+
+int link_deserialize_addresses(Link *link, const char *addresses) {
+        int r;
+
+        assert(link);
+
+        for (const char *p = addresses;; ) {
+                _cleanup_(address_freep) Address *tmp = NULL;
+                _cleanup_free_ char *address_str = NULL;
+
+                r = extract_first_word(&p, &address_str, NULL, 0);
+                if (r < 0)
+                        return log_link_debug_errno(link, r, "Failed to parse ADDRESSES=: %m");
+                if (r == 0)
+                        return 0;
+
+                r = address_new(&tmp);
+                if (r < 0)
+                        return log_oom();
+
+                r = in_addr_prefix_from_string_auto(address_str, &tmp->family, &tmp->in_addr, &tmp->prefixlen);
+                if (r < 0) {
+                        log_link_debug_errno(link, r, "Failed to parse address, ignoring: %s", address_str);
+                        continue;
+                }
+
+                r = address_add(link, tmp, NULL);
+                if (r < 0)
+                        log_link_debug_errno(link, r, "Failed to add address %s, ignoring: %m", address_str);
+        }
+
+        return 0;
+}
+
+static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+        _cleanup_free_ char *pretty = NULL;
+        Address *address;
+        Link *link;
+        int r;
+
+        assert(acd);
+        assert(userdata);
+
+        address = (Address *) userdata;
+        link = address->link;
+
+        (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
+        switch (event) {
+        case SD_IPV4ACD_EVENT_STOP:
+                log_link_debug(link, "Stopping ACD client...");
+                return;
+
+        case SD_IPV4ACD_EVENT_BIND:
+                log_link_debug(link, "Successfully claimed address %s", strna(pretty));
+                link_check_ready(link);
                 break;
 
         case SD_IPV4ACD_EVENT_CONFLICT:
@@ -783,48 +1338,123 @@ static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
                 assert_not_reached("Invalid IPv4ACD event.");
         }
 
-        sd_ipv4acd_stop(acd);
+        (void) sd_ipv4acd_stop(acd);
 
         return;
 }
 
-int configure_ipv4_duplicate_address_detection(Link *link, Address *address) {
+static int ipv4_dad_configure(Address *address) {
         int r;
 
-        assert(link);
         assert(address);
-        assert(address->family == AF_INET);
-        assert(!address->link && address->network);
+        assert(address->link);
 
-        address->link = link;
+        if (address->family != AF_INET)
+                return 0;
+
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *pretty = NULL;
+
+                (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
+                log_link_debug(address->link, "Starting IPv4ACD client. Probing address %s", strna(pretty));
+        }
 
-        r = sd_ipv4acd_new(&address->acd);
+        if (!address->acd) {
+                r = sd_ipv4acd_new(&address->acd);
+                if (r < 0)
+                        return r;
+
+                r = sd_ipv4acd_attach_event(address->acd, address->link->manager->event, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_ipv4acd_set_ifindex(address->acd, address->link->ifindex);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_attach_event(address->acd, NULL, 0);
+        r = sd_ipv4acd_set_mac(address->acd, &address->link->mac);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
+        r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_mac(address->acd, &link->mac);
+        r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
+        return sd_ipv4acd_start(address->acd, true);
+}
+
+static int ipv4_dad_update_mac_one(Address *address) {
+        bool running;
+        int r;
+
+        assert(address);
+
+        if (!address->acd)
+                return 0;
+
+        running = sd_ipv4acd_is_running(address->acd);
+
+        r = sd_ipv4acd_stop(address->acd);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
+        r = sd_ipv4acd_set_mac(address->acd, &address->link->mac);
         if (r < 0)
                 return r;
 
+        if (running) {
+                r = sd_ipv4acd_start(address->acd, true);
+                if (r < 0)
+                        return r;
+        }
+
         return 0;
 }
 
+int ipv4_dad_update_mac(Link *link) {
+        Address *address;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(address, link->addresses) {
+                k = ipv4_dad_update_mac_one(address);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+int ipv4_dad_stop(Link *link) {
+        Address *address;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(address, link->addresses) {
+                k = sd_ipv4acd_stop(address->acd);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+void ipv4_dad_unref(Link *link) {
+        Address *address;
+
+        assert(link);
+
+        SET_FOREACH(address, link->addresses)
+                address->acd = sd_ipv4acd_unref(address->acd);
+}
+
 int config_parse_broadcast(
                 const char *unit,
                 const char *filename,
@@ -875,7 +1505,8 @@ int config_parse_broadcast(
         return 0;
 }
 
-int config_parse_address(const char *unit,
+int config_parse_address(
+                const char *unit,
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -898,11 +1529,10 @@ int config_parse_address(const char *unit,
         assert(rvalue);
         assert(data);
 
-        if (streq(section, "Network")) {
-                /* we are not in an Address section, so treat
-                 * this as the special '0' section */
-                r = address_new_static(network, NULL, 0, &n);
-        } else
+        if (streq(section, "Network"))
+                /* we are not in an Address section, so use line number instead. */
+                r = address_new_static(network, filename, line, &n);
+        else
                 r = address_new_static(network, filename, section_line, &n);
         if (r == -ENOMEM)
                 return log_oom();
@@ -953,9 +1583,6 @@ int config_parse_address(const char *unit,
         else
                 n->in_addr_peer = buffer;
 
-        if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
-                n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
-
         n = NULL;
 
         return 0;
@@ -1006,16 +1633,18 @@ int config_parse_label(
         return 0;
 }
 
-int config_parse_lifetime(const char *unit,
-                          const char *filename,
-                          unsigned line,
-                          const char *section,
-                          unsigned section_line,
-                          const char *lvalue,
-                          int ltype,
-                          const char *rvalue,
-                          void *data,
-                          void *userdata) {
+int config_parse_lifetime(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         uint32_t k;
@@ -1053,16 +1682,18 @@ int config_parse_lifetime(const char *unit,
         return 0;
 }
 
-int config_parse_address_flags(const char *unit,
-                               const char *filename,
-                               unsigned line,
-                               const char *section,
-                               unsigned section_line,
-                               const char *lvalue,
-                               int ltype,
-                               const char *rvalue,
-                               void *data,
-                               void *userdata) {
+int config_parse_address_flags(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         int r;
@@ -1089,33 +1720,27 @@ int config_parse_address_flags(const char *unit,
                 return 0;
         }
 
-        if (streq(lvalue, "HomeAddress"))
-                n->home_address = r;
-        else if (streq(lvalue, "ManageTemporaryAddress"))
-                n->manage_temporary_address = r;
-        else if (streq(lvalue, "PrefixRoute"))
-                n->prefix_route = !r;
-        else if (streq(lvalue, "AddPrefixRoute"))
-                n->prefix_route = r;
-        else if (streq(lvalue, "AutoJoin"))
-                n->autojoin = r;
-        else
-                assert_not_reached("Invalid address flag type.");
+        if (streq(lvalue, "AddPrefixRoute"))
+                r = !r;
+
+        SET_FLAG(n->flags, ltype, r);
 
         n = NULL;
         return 0;
 }
 
-int config_parse_address_scope(const char *unit,
-                               const char *filename,
-                               unsigned line,
-                               const char *section,
-                               unsigned section_line,
-                               const char *lvalue,
-                               int ltype,
-                               const char *rvalue,
-                               void *data,
-                               void *userdata) {
+int config_parse_address_scope(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         int r;
@@ -1166,6 +1791,7 @@ int config_parse_duplicate_address_detection(
                 const char *rvalue,
                 void *data,
                 void *userdata) {
+
         Network *network = userdata;
         _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         AddressFamily a;
@@ -1215,7 +1841,7 @@ bool address_is_ready(const Address *a) {
         return !(a->flags & IFA_F_TENTATIVE);
 }
 
-int address_section_verify(Address *address) {
+static int address_section_verify(Address *address) {
         if (section_is_invalid(address->section))
                 return -EINVAL;
 
@@ -1228,8 +1854,51 @@ int address_section_verify(Address *address) {
                                          address->section->filename, address->section->line);
         }
 
-        if (!address->scope_set && in_addr_is_localhost(address->family, &address->in_addr) > 0)
+        if (address->family == AF_INET && in_addr_is_null(address->family, &address->in_addr_peer) &&
+            address->broadcast.s_addr == 0 && address->prefixlen <= 30)
+                address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
+        else if (address->broadcast.s_addr != 0) {
+                log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
+                            "Ignoring Broadcast= setting in the [Address] section from line %u.",
+                            address->section->filename, address->section->line);
+
+                address->broadcast.s_addr = 0;
+        }
+
+        if (address->family == AF_INET6 && address->label) {
+                log_warning("%s: address label is set for IPv6 address in the [Address] section from line %u. "
+                            "Ignoring Label= setting.",
+                            address->section->filename, address->section->line);
+
+                address->label = mfree(address->label);
+        }
+
+        if (in_addr_is_localhost(address->family, &address->in_addr) > 0 &&
+            (address->family == AF_INET || !address->scope_set)) {
+                /* For IPv4, scope must be always RT_SCOPE_HOST.
+                 * For IPv6, use RT_SCOPE_HOST only when it is not explicitly specified. */
+
+                if (address->scope_set && address->scope != RT_SCOPE_HOST)
+                        log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                          "%s: non-host scope is set in the [Address] section from line %u. "
+                                          "Ignoring Scope= setting.",
+                                          address->section->filename, address->section->line);
+
                 address->scope = RT_SCOPE_HOST;
+        }
+
+        if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6))
+                address->flags |= IFA_F_NODAD;
 
         return 0;
 }
+
+void network_drop_invalid_addresses(Network *network) {
+        Address *address;
+
+        assert(network);
+
+        ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
+                if (address_section_verify(address) < 0)
+                        address_free(address);
+}
index 1378901b8b1c3361e685f36f8d0038cff493a921..0104747d9a5da713594bd29897f3053216c7dfdd 100644 (file)
@@ -3,26 +3,22 @@
 
 #include <inttypes.h>
 #include <stdbool.h>
+#include <stdio.h>
+
+#include "sd-ipv4acd.h"
 
 #include "conf-parser.h"
 #include "in-addr-util.h"
-
-typedef struct Address Address;
-
 #include "networkd-link.h"
-#include "networkd-network.h"
 #include "networkd-util.h"
 
-#include "sd-ipv4acd.h"
-
 #define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
 
+typedef struct Manager Manager;
 typedef struct Network Network;
-typedef struct Link Link;
-typedef struct NetworkConfigSection NetworkConfigSection;
 typedef int (*address_ready_callback_t)(Address *address);
 
-struct Address {
+typedef struct Address {
         Network *network;
         NetworkConfigSection *section;
 
@@ -42,39 +38,41 @@ struct Address {
 
         bool scope_set:1;
         bool ip_masquerade_done:1;
-        bool manage_temporary_address:1;
-        bool home_address:1;
-        bool prefix_route:1;
-        bool autojoin:1;
         AddressFamily duplicate_address_detection;
 
         /* Called when address become ready */
         address_ready_callback_t callback;
 
         sd_ipv4acd *acd;
-
-        LIST_FIELDS(Address, addresses);
-};
+} Address;
 
 int address_new(Address **ret);
-void address_free(Address *address);
-int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
-int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
-int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+Address *address_free(Address *address);
+int address_get(Link *link, const Address *in, Address **ret);
 bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
-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, link_netlink_message_handler_t callback, bool update, Address **ret);
-int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
-bool address_equal(Address *a1, Address *a2);
+int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
+int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback);
+bool address_equal(const Address *a1, const Address *a2);
 bool address_is_ready(const Address *a);
-int address_section_verify(Address *a);
-int configure_ipv4_duplicate_address_detection(Link *link, Address *address);
 
-int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
+int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret);
 
 DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
 
+int link_set_addresses(Link *link);
+int link_drop_addresses(Link *link);
+int link_drop_foreign_addresses(Link *link);
+int link_serialize_addresses(Link *link, FILE *f);
+int link_deserialize_addresses(Link *link, const char *addresses);
+
+void ipv4_dad_unref(Link *link);
+int ipv4_dad_stop(Link *link);
+int ipv4_dad_update_mac(Link *link);
+
+int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m);
+
+void network_drop_invalid_addresses(Network *network);
+
 void address_hash_func(const Address *a, struct siphash *state);
 int address_compare_func(const Address *a1, const Address *a2);
 extern const struct hash_ops address_hash_ops;
@@ -86,3 +84,10 @@ CONFIG_PARSER_PROTOTYPE(config_parse_lifetime);
 CONFIG_PARSER_PROTOTYPE(config_parse_address_flags);
 CONFIG_PARSER_PROTOTYPE(config_parse_address_scope);
 CONFIG_PARSER_PROTOTYPE(config_parse_duplicate_address_detection);
+
+#define IPV4_ADDRESS_FMT_STR     "%u.%u.%u.%u"
+#define IPV4_ADDRESS_FMT_VAL(address)              \
+        be32toh((address).s_addr) >> 24,           \
+        (be32toh((address).s_addr) >> 16) & 0xFFu, \
+        (be32toh((address).s_addr) >> 8) & 0xFFu,  \
+        be32toh((address).s_addr) & 0xFFu
index bbe01037d1773a47ebf62d570675ede2b60df19f..23ca4f9fac84af2dd8f15182fb51f4d9f616f5ee 100644 (file)
@@ -146,26 +146,26 @@ static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *lin
         return 1;
 }
 
-int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
+int link_set_bridge_vlan(Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        sd_netlink *rtnl;
-        uint16_t flags;
         int r;
 
         assert(link);
         assert(link->manager);
-        assert(br_vid_bitmap);
-        assert(br_untagged_bitmap);
         assert(link->network);
 
-        /* pvid might not be in br_vid_bitmap yet */
-        if (pvid)
-                set_bit(pvid, br_vid_bitmap);
+        if (!link->network->use_br_vlan)
+                return 0;
 
-        rtnl = link->manager->rtnl;
+        if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
+                return 0;
+
+        /* pvid might not be in br_vid_bitmap yet */
+        if (link->network->pvid)
+                set_bit(link->network->pvid, link->network->br_vid_bitmap);
 
         /* create new RTM message */
-        r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
@@ -179,14 +179,14 @@ int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32
 
         /* master needs flag self */
         if (!link->network->bridge) {
-                flags = BRIDGE_FLAGS_SELF;
-                r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
+                uint16_t flags = BRIDGE_FLAGS_SELF;
+                r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(flags));
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not open IFLA_BRIDGE_FLAGS: %m");
         }
 
         /* add vlan info */
-        r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
+        r = append_vlan_info_data(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append VLANs: %m");
 
@@ -195,7 +195,7 @@ 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 = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
+        r = netlink_call_async(link->manager->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 7533034021690c9ec7694e0b08109e17a385ff53..d13ea30151eae6ec72f6ba352f86f8eeae722d43 100644 (file)
@@ -5,8 +5,6 @@
   Copyright © 2016 BISDN GmbH. All rights reserved.
 ***/
 
-#include <stdint.h>
-
 #include "conf-parser.h"
 
 #define BRIDGE_VLAN_BITMAP_MAX 4096
@@ -14,7 +12,7 @@
 
 typedef struct Link Link;
 
-int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap);
+int link_set_bridge_vlan(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_pvid);
 CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_vlan);
index ecf9bcea85728f1fa6d7b261bd8bcc01b00da889..a41bd348dc4bfb04f1c24d6f1f3307e7b6c3b676 100644 (file)
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <netinet/in.h>
+#include <linux/if_arp.h>
+
 #include "dhcp-internal.h"
 #include "dhcp6-internal.h"
 #include "escape.h"
 #include "in-addr-util.h"
 #include "networkd-dhcp-common.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
 #include "networkd-network.h"
 #include "parse-util.h"
+#include "socket-util.h"
 #include "string-table.h"
 #include "strv.h"
 
+bool link_dhcp_enabled(Link *link, int family) {
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+
+        if (family == AF_INET6 && !socket_ipv6_is_supported())
+                return false;
+
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (link->iftype == ARPHRD_CAN)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        return link->network->dhcp & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
+}
+
+void network_adjust_dhcp(Network *network) {
+        assert(network);
+        assert(network->dhcp >= 0);
+
+        if (network->dhcp == ADDRESS_FAMILY_NO)
+                return;
+
+        /* Bonding slave does not support addressing. */
+        if (network->bond) {
+                log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
+                            network->filename);
+                network->dhcp = ADDRESS_FAMILY_NO;
+                return;
+        }
+
+        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) &&
+            FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
+                log_warning("%s: DHCPv6 client is enabled but IPv6 link local addressing is disabled. "
+                            "Disabling DHCPv6 client.", network->filename);
+                SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
+        }
+}
+
+DUID* link_get_duid(Link *link) {
+        if (link->network->duid.type != _DUID_TYPE_INVALID)
+                return &link->network->duid;
+        else
+                return &link->manager->duid;
+}
+
+static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
+        assert(duid);
+
+        if (duid->raw_data_len > 0)
+                return 0;
+
+        if (duid->type != DUID_TYPE_UUID)
+                return -EINVAL;
+
+        memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
+        duid->raw_data_len = sizeof(sd_id128_t);
+
+        return 1;
+}
+
+static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        Manager *manager = userdata;
+        const sd_bus_error *e;
+        const void *a;
+        size_t sz;
+        DUID *duid;
+        Link *link;
+        int r;
+
+        assert(m);
+        assert(manager);
+
+        e = sd_bus_message_get_error(m);
+        if (e) {
+                log_error_errno(sd_bus_error_get_errno(e),
+                                "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
+                                e->message);
+                goto configure;
+        }
+
+        r = sd_bus_message_read_array(m, 'y', &a, &sz);
+        if (r < 0)
+                goto configure;
+
+        if (sz != sizeof(sd_id128_t)) {
+                log_error("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
+                goto configure;
+        }
+
+        memcpy(&manager->product_uuid, a, sz);
+        while ((duid = set_steal_first(manager->duids_requesting_uuid)))
+                (void) duid_set_uuid(duid, manager->product_uuid);
+
+        manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
+
+configure:
+        while ((link = set_steal_first(manager->links_requesting_uuid))) {
+                link_unref(link);
+
+                r = link_configure(link);
+                if (r < 0)
+                        link_enter_failed(link);
+        }
+
+        manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
+
+        /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
+         * even if the method fails. */
+        manager->has_product_uuid = true;
+
+        return 1;
+}
+
+int manager_request_product_uuid(Manager *m, Link *link) {
+        int r;
+
+        assert(m);
+
+        if (m->has_product_uuid)
+                return 0;
+
+        log_debug("Requesting product UUID");
+
+        if (link) {
+                DUID *duid;
+
+                assert_se(duid = link_get_duid(link));
+
+                r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
+                if (r < 0)
+                        return log_oom();
+                if (r > 0)
+                        link_ref(link);
+
+                r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
+                log_debug("Not connected to system bus, requesting product UUID later.");
+                return 0;
+        }
+
+        r = sd_bus_call_method_async(
+                        m->bus,
+                        NULL,
+                        "org.freedesktop.hostname1",
+                        "/org/freedesktop/hostname1",
+                        "org.freedesktop.hostname1",
+                        "GetProductUUID",
+                        get_product_uuid_handler,
+                        m,
+                        "b",
+                        false);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to get product UUID: %m");
+
+        return 0;
+}
+
+static bool link_requires_uuid(Link *link) {
+        const DUID *duid;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->network);
+
+        duid = link_get_duid(link);
+        if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
+                return false;
+
+        if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
+                return true;
+
+        if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
+                return true;
+
+        return false;
+}
+
+int link_configure_duid(Link *link) {
+        Manager *m;
+        DUID *duid;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->network);
+
+        m = link->manager;
+        duid = link_get_duid(link);
+
+        if (!link_requires_uuid(link))
+                return 1;
+
+        if (m->has_product_uuid) {
+                (void) duid_set_uuid(duid, m->product_uuid);
+                return 1;
+        }
+
+        if (!m->links_requesting_uuid) {
+                r = manager_request_product_uuid(m, link);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                return r;
+
+                        log_link_warning_errno(link, r,
+                                               "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
+                        return 1;
+                }
+        } else {
+                r = set_put(m->links_requesting_uuid, link);
+                if (r < 0)
+                        return log_oom();
+                if (r > 0)
+                        link_ref(link);
+
+                r = set_put(m->duids_requesting_uuid, duid);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        return 0;
+}
+
 int config_parse_dhcp(
                 const char* unit,
                 const char *filename,
@@ -546,10 +782,9 @@ int config_parse_dhcp_send_option(
         }
         case DHCP_OPTION_DATA_STRING:
                 sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q);
-                if (sz < 0) {
+                if (sz < 0)
                         log_syntax(unit, LOG_WARNING, filename, line, sz,
                                    "Failed to decode DHCP option data, ignoring assignment: %s", p);
-                }
 
                 udata = q;
                 break;
index 01400a23858d4cbe200800956560b5f598d43c20..fc84450e5eb5e8a2266f200fc6ac34164c3861d4 100644 (file)
@@ -7,6 +7,10 @@
 
 #define DHCP_ROUTE_METRIC 1024
 
+typedef struct Link Link;
+typedef struct Manager Manager;
+typedef struct Network Network;
+
 typedef enum DHCPUseDomains {
         DHCP_USE_DOMAINS_NO,
         DHCP_USE_DOMAINS_YES,
@@ -35,6 +39,20 @@ typedef struct DUID {
         usec_t llt_time;
 } DUID;
 
+bool link_dhcp_enabled(Link *link, int family);
+static inline bool link_dhcp4_enabled(Link *link) {
+        return link_dhcp_enabled(link, AF_INET);
+}
+static inline bool link_dhcp6_enabled(Link *link) {
+        return link_dhcp_enabled(link, AF_INET6);
+}
+
+void network_adjust_dhcp(Network *network);
+
+DUID* link_get_duid(Link *link);
+int link_configure_duid(Link *link);
+int manager_request_product_uuid(Manager *m, Link *link);
+
 const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
 DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;
 
index 890d9b55a11a5acdee282f821609a485f862025f..0155ab2de2a5128cef79276b6e5d0c26ab51e7e6 100644 (file)
@@ -1,9 +1,14 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <netinet/in.h>
+#include <linux/if_arp.h>
+#include <linux/if.h>
+
 #include "sd-dhcp-server.h"
 
 #include "fd-util.h"
 #include "fileio.h"
+#include "networkd-address.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "string-util.h"
 #include "strv.h"
 
+static bool link_dhcp4_server_enabled(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        if (link->network->bond)
+                return false;
+
+        if (link->iftype == ARPHRD_CAN)
+                return false;
+
+        return link->network->dhcp_server;
+}
+
 static Address* link_find_dhcp_server_address(Link *link) {
         Address *address;
 
@@ -21,13 +44,13 @@ static Address* link_find_dhcp_server_address(Link *link) {
         assert(link->network);
 
         /* The first statically configured address if there is any */
-        LIST_FOREACH(addresses, address, link->network->static_addresses)
+        ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section)
                 if (address->family == AF_INET &&
                     !in_addr_is_null(address->family, &address->in_addr))
                         return address;
 
         /* If that didn't work, find a suitable address we got from the pool */
-        LIST_FOREACH(addresses, address, link->pool_addresses)
+        SET_FOREACH(address, link->pool_addresses)
                 if (address->family == AF_INET)
                         return address;
 
@@ -230,6 +253,24 @@ int dhcp4_server_configure(Link *link) {
         Address *address;
         int r;
 
+        assert(link);
+
+        if (!link_dhcp4_server_enabled(link))
+                return 0;
+
+        if (!(link->flags & IFF_UP))
+                return 0;
+
+        if (!link->dhcp_server) {
+                r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
+                if (r < 0)
+                        return r;
+
+                r = sd_dhcp_server_attach_event(link->dhcp_server, link->manager->event, 0);
+                if (r < 0)
+                        return r;
+        }
+
         address = link_find_dhcp_server_address(link);
         if (!address)
                 return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY),
@@ -341,6 +382,8 @@ int dhcp4_server_configure(Link *link) {
                 r = sd_dhcp_server_start(link->dhcp_server);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
+
+                log_link_debug(link, "Offering DHCPv4 leases");
         }
 
         return 0;
index eddeb0d5ef727f2d144f108cc4a867f0ed41a23e..bb8c34f7cc5959c048e21a3a6b61c73cb54453ec 100644 (file)
@@ -11,6 +11,7 @@
 #include "hostname-util.h"
 #include "parse-util.h"
 #include "network-internal.h"
+#include "networkd-address.h"
 #include "networkd-dhcp4.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
@@ -37,7 +38,7 @@ static int dhcp4_release_old_lease(Link *link) {
         link_dirty(link);
 
         SET_FOREACH(route, link->dhcp_routes_old) {
-                k = route_remove(route, link, NULL);
+                k = route_remove(route, NULL, link, NULL);
                 if (k < 0)
                         r = k;
         }
@@ -311,6 +312,7 @@ static int link_set_dhcp_routes(Link *link) {
 
                         route->family = AF_INET;
                         route->protocol = RTPROT_DHCP;
+                        route->gw_family = AF_INET;
                         assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
                         assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
                         assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
@@ -373,6 +375,7 @@ static int link_set_dhcp_routes(Link *link) {
                                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
                         route->family = AF_INET;
+                        route->gw_family = AF_INET;
                         route->gw.in = router[0];
                         route->prefsrc.in = address;
                         route->protocol = RTPROT_DHCP;
@@ -384,14 +387,22 @@ static int link_set_dhcp_routes(Link *link) {
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Could not set router: %m");
 
-                        LIST_FOREACH(routes, rt, link->network->static_routes) {
-                                if (!rt->gateway_from_dhcp)
+                        HASHMAP_FOREACH(rt, link->network->routes_by_section) {
+                                if (!rt->gateway_from_dhcp_or_ra)
                                         continue;
 
-                                if (rt->family != AF_INET)
+                                if (rt->gw_family != AF_INET)
                                         continue;
 
                                 rt->gw.in = router[0];
+                                if (!rt->protocol_set)
+                                        rt->protocol = RTPROT_DHCP;
+                                if (!rt->priority_set)
+                                        rt->priority = link->network->dhcp_route_metric;
+                                if (!rt->table_set)
+                                        rt->table = table;
+                                if (rt->mtu == 0)
+                                        rt->mtu = link->network->dhcp_route_mtu;
 
                                 r = dhcp_route_configure(rt, link);
                                 if (r < 0)
@@ -511,7 +522,7 @@ static int dhcp4_remove_all(Link *link) {
         assert(link);
 
         SET_FOREACH(route, link->dhcp_routes) {
-                k = route_remove(route, link, dhcp4_remove_route_handler);
+                k = route_remove(route, NULL, link, dhcp4_remove_route_handler);
                 if (k < 0)
                         r = k;
                 else
@@ -559,6 +570,8 @@ static int dhcp_lease_lost(Link *link) {
         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
         link_dirty(link);
 
+        (void) sd_ipv4acd_stop(link->dhcp_acd);
+
         return r;
 }
 
@@ -613,27 +626,62 @@ static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
         return;
 }
 
-static int configure_dhcpv4_duplicate_address_detection(Link *link) {
+static int dhcp4_configure_dad(Link *link) {
         int r;
 
         assert(link);
+        assert(link->manager);
+        assert(link->network);
+
+        if (!link->network->dhcp_send_decline)
+                return 0;
 
-        r = sd_ipv4acd_new(&link->network->dhcp_acd);
+        if (!link->dhcp_acd) {
+                r = sd_ipv4acd_new(&link->dhcp_acd);
+                if (r < 0)
+                        return r;
+
+                r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_attach_event(link->network->dhcp_acd, NULL, 0);
+        r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_ifindex(link->network->dhcp_acd, link->ifindex);
+        return 0;
+}
+
+static int dhcp4_dad_update_mac(Link *link) {
+        bool running;
+        int r;
+
+        assert(link);
+
+        if (!link->dhcp_acd)
+                return 0;
+
+        running = sd_ipv4acd_is_running(link->dhcp_acd);
+
+        r = sd_ipv4acd_stop(link->dhcp_acd);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_mac(link->network->dhcp_acd, &link->mac);
+        r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac);
         if (r < 0)
                 return r;
 
+        if (running) {
+                r = sd_ipv4acd_start(link->dhcp_acd, true);
+                if (r < 0)
+                        return r;
+        }
+
         return 0;
 }
 
@@ -648,7 +696,7 @@ static int dhcp4_start_acd(Link *link) {
         if (!link->dhcp_lease)
                 return 0;
 
-        (void) sd_ipv4acd_stop(link->network->dhcp_acd);
+        (void) sd_ipv4acd_stop(link->dhcp_acd);
 
         link->dhcp4_address_bind = false;
 
@@ -656,15 +704,15 @@ static int dhcp4_start_acd(Link *link) {
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_get_address(link->network->dhcp_acd, &old);
+        r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_address(link->network->dhcp_acd, &addr.in);
+        r = sd_ipv4acd_set_address(link->dhcp_acd, &addr.in);
         if (r < 0)
                 return r;
 
-        r = sd_ipv4acd_set_callback(link->network->dhcp_acd, dhcp_address_on_acd, link);
+        r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
         if (r < 0)
                 return r;
 
@@ -675,7 +723,7 @@ static int dhcp4_start_acd(Link *link) {
                 log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
         }
 
-        r = sd_ipv4acd_start(link->network->dhcp_acd, !in4_addr_equal(&addr.in, &old));
+        r = sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr.in, &old));
         if (r < 0)
                 return r;
 
@@ -698,7 +746,7 @@ static int dhcp4_address_ready_callback(Address *address) {
                 return r;
 
         /* Reconfigure static routes as kernel may remove some routes when lease expires. */
-        r = link_request_set_routes(link);
+        r = link_set_routes(link);
         if (r < 0)
                 return r;
 
@@ -755,9 +803,9 @@ static int dhcp4_update_address(Link *link, bool announce) {
         link_set_state(link, LINK_STATE_CONFIGURING);
         link->dhcp4_configured = false;
 
-        /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they
-         * are called, the related flags must be cleared. Otherwise, the link becomes configured state
-         * before routes are configured. */
+        /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are called, the
+         * related flags must be cleared. Otherwise, the link becomes configured state before routes
+         * are configured. */
         link->static_routes_configured = false;
         link->static_nexthops_configured = false;
 
@@ -787,20 +835,20 @@ static int dhcp4_update_address(Link *link, bool announce) {
                 if (r > 0 && !in4_addr_is_null(&router[0]))
                         log_struct(LOG_INFO,
                                    LOG_LINK_INTERFACE(link),
-                                   LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
-                                                    ADDRESS_FMT_VAL(address),
+                                   LOG_LINK_MESSAGE(link, "DHCPv4 address "IPV4_ADDRESS_FMT_STR"/%u via "IPV4_ADDRESS_FMT_STR,
+                                                    IPV4_ADDRESS_FMT_VAL(address),
                                                     prefixlen,
-                                                    ADDRESS_FMT_VAL(router[0])),
-                                   "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
+                                                    IPV4_ADDRESS_FMT_VAL(router[0])),
+                                   "ADDRESS="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address),
                                    "PREFIXLEN=%u", prefixlen,
-                                   "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
+                                   "GATEWAY="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(router[0]));
                 else
                         log_struct(LOG_INFO,
                                    LOG_LINK_INTERFACE(link),
-                                   LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
-                                                    ADDRESS_FMT_VAL(address),
+                                   LOG_LINK_MESSAGE(link, "DHCPv4 address "IPV4_ADDRESS_FMT_STR"/%u",
+                                                    IPV4_ADDRESS_FMT_VAL(address),
                                                     prefixlen),
-                                   "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
+                                   "ADDRESS="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address),
                                    "PREFIXLEN=%u", prefixlen);
         }
 
@@ -814,7 +862,7 @@ static int dhcp4_update_address(Link *link, bool announce) {
         addr->cinfo.ifa_valid = lifetime;
         addr->prefixlen = prefixlen;
         addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
-        addr->prefix_route = link_prefixroute(link);
+        SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
 
         /* allow reusing an existing address and simply update its lifetime
          * in case it already exists */
@@ -951,8 +999,8 @@ static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {
         if (set_contains(link->network->dhcp_deny_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
                 log_struct(LOG_DEBUG,
                            LOG_LINK_INTERFACE(link),
-                           LOG_LINK_MESSAGE(link, "DHCPv4 IP '%u.%u.%u.%u' found in deny-listed IP addresses, ignoring offer",
-                                            ADDRESS_FMT_VAL(addr)));
+                           LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in deny-list, ignoring offer",
+                                            IPV4_ADDRESS_FMT_VAL(addr)));
                 return true;
         }
 
@@ -979,8 +1027,8 @@ static int dhcp_server_is_allow_listed(Link *link, sd_dhcp_client *client) {
         if (set_contains(link->network->dhcp_allow_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
                 log_struct(LOG_DEBUG,
                            LOG_LINK_INTERFACE(link),
-                           LOG_LINK_MESSAGE(link, "DHCPv4 IP '%u.%u.%u.%u' found in allow-listed IP addresses, accepting offer",
-                                            ADDRESS_FMT_VAL(addr)));
+                           LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in allow-list, accepting offer",
+                                            IPV4_ADDRESS_FMT_VAL(addr)));
                 return true;
         }
 
@@ -1156,12 +1204,10 @@ static bool promote_secondaries_enabled(const char *ifname) {
  * the primary one expires it relies on the kernel to promote the
  * secondary IP. See also https://github.com/systemd/systemd/issues/7163
  */
-int dhcp4_set_promote_secondaries(Link *link) {
+static int dhcp4_set_promote_secondaries(Link *link) {
         int r;
 
         assert(link);
-        assert(link->network);
-        assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
 
         /* check if the kernel has promote_secondaries enabled for our
          * interface. If it is not globally enabled or enabled for the
@@ -1181,7 +1227,7 @@ int dhcp4_set_promote_secondaries(Link *link) {
         return 0;
 }
 
-int dhcp4_set_client_identifier(Link *link) {
+static int dhcp4_set_client_identifier(Link *link) {
         int r;
 
         assert(link);
@@ -1240,6 +1286,25 @@ int dhcp4_set_client_identifier(Link *link) {
         return 0;
 }
 
+static int dhcp4_init(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (link->dhcp_client)
+                return 0;
+
+        r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
+        if (r < 0)
+                return r;
+
+        r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int dhcp4_configure(Link *link) {
         sd_dhcp_option *send_option;
         void *request_options;
@@ -1247,19 +1312,17 @@ int dhcp4_configure(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
 
-        if (!link->dhcp_client) {
-                r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
-                if (r == -ENOMEM)
-                        return log_oom();
-                if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to create DHCP4 client: %m");
+        if (!link_dhcp4_enabled(link))
+                return 0;
 
-                r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to attach event: %m");
-        }
+        r = dhcp4_set_promote_secondaries(link);
+        if (r < 0)
+                return r;
+
+        r = dhcp4_init(link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to initialize DHCP4 client: %m");
 
         r = sd_dhcp_client_set_mac(link->dhcp_client,
                                    (const uint8_t *) &link->mac,
@@ -1338,10 +1401,6 @@ int dhcp4_configure(Link *link) {
                 uint32_t option = PTR_TO_UINT32(request_options);
 
                 r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
-                if (r == -EEXIST) {
-                        log_link_debug(link, "DHCP4 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
-                        continue;
-                }
                 if (r < 0)
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
         }
@@ -1398,8 +1457,8 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
         }
 
-        if (link->network->ip_service_type > 0) {
-                r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->ip_service_type);
+        if (link->network->dhcp_ip_service_type > 0) {
+                r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
                 if (r < 0)
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
         }
@@ -1410,15 +1469,60 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
         }
 
-        if (link->network->dhcp_send_decline) {
-                r = configure_dhcpv4_duplicate_address_detection(link);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
-        }
+        r = dhcp4_configure_dad(link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
 
         return dhcp4_set_client_identifier(link);
 }
 
+int dhcp4_update_mac(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (!link->dhcp_client)
+                return 0;
+
+        r = sd_dhcp_client_set_mac(link->dhcp_client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER);
+        if (r < 0)
+                return r;
+
+        r = dhcp4_set_client_identifier(link);
+        if (r < 0)
+                return r;
+
+        r = dhcp4_dad_update_mac(link);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int link_deserialize_dhcp4(Link *link, const char *dhcp4_address) {
+        union in_addr_union address;
+        int r;
+
+        assert(link);
+
+        if (isempty(dhcp4_address))
+                return 0;
+
+        r = in_addr_from_string(AF_INET, dhcp4_address, &address);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to parse DHCPv4 address: %s", dhcp4_address);
+
+        r = dhcp4_init(link);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to initialize DHCPv4 client: %m");
+
+        r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to set initial DHCPv4 address %s: %m", dhcp4_address);
+
+        return 0;
+}
+
 int config_parse_dhcp_max_attempts(
                 const char *unit,
                 const char *filename,
index 7a80897ffcdd6e9f0bca2fd85ccee313474712cd..8aa6ac9453eacd271e9cf6ed836651c2208ad88d 100644 (file)
@@ -18,8 +18,9 @@ typedef enum DHCPClientIdentifier {
 } DHCPClientIdentifier;
 
 int dhcp4_configure(Link *link);
-int dhcp4_set_client_identifier(Link *link);
-int dhcp4_set_promote_secondaries(Link *link);
+int dhcp4_update_mac(Link *link);
+
+int link_deserialize_dhcp4(Link *link, const char *dhcp4_address);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
index 7996e825c29a95d89b111cb84b9a9f8dd2d6fffe..d9cc4ccf41326ef4517dd261947c480c8ecd94a6 100644 (file)
@@ -14,6 +14,7 @@
 #include "hostname-util.h"
 #include "missing_network.h"
 #include "network-internal.h"
+#include "networkd-address.h"
 #include "networkd-dhcp6.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "radv-internal.h"
 #include "web-util.h"
 
+bool link_dhcp6_pd_is_enabled(Link *link) {
+        assert(link);
+
+        if (!link->network)
+                return false;
+
+        return link->network->dhcp6_pd;
+}
+
 static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
         uint32_t lifetime_preferred, lifetime_valid;
         union in_addr_union pd_prefix;
@@ -154,7 +164,7 @@ static int dhcp6_pd_remove_old(Link *link, bool force) {
         link_dirty(link);
 
         SET_FOREACH(route, link->dhcp6_pd_routes_old) {
-                k = route_remove(route, link, NULL);
+                k = route_remove(route, NULL, link, NULL);
                 if (k < 0)
                         r = k;
 
@@ -180,6 +190,9 @@ int dhcp6_pd_remove(Link *link) {
         assert(link);
         assert(link->manager);
 
+        if (!link_dhcp6_pd_is_enabled(link))
+                return 0;
+
         link->dhcp6_pd_address_configured = false;
         link->dhcp6_pd_route_configured = false;
 
@@ -195,7 +208,7 @@ int dhcp6_pd_remove(Link *link) {
         link_dirty(link);
 
         SET_FOREACH(route, link->dhcp6_pd_routes) {
-                k = route_remove(route, link, NULL);
+                k = route_remove(route, NULL, link, NULL);
                 if (k < 0)
                         r = k;
 
@@ -342,7 +355,7 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
                         return 1;
                 }
 
-                r = link_request_set_routes(link);
+                r = link_set_routes(link);
                 if (r < 0) {
                         link_enter_failed(link);
                         return 1;
@@ -408,11 +421,14 @@ static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix,
         int r;
 
         assert(link);
+        assert(link->network);
         assert(prefix);
 
-        r = radv_add_prefix(link, &prefix->in6, prefix_len, lifetime_preferred, lifetime_valid);
-        if (r < 0)
-                return r;
+        if (link->network->dhcp6_pd_announce) {
+                r = radv_add_prefix(link, &prefix->in6, prefix_len, lifetime_preferred, lifetime_valid);
+                if (r < 0)
+                        return r;
+        }
 
         r = dhcp6_set_pd_route(link, prefix, pd_prefix);
         if (r < 0)
@@ -425,13 +441,6 @@ static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix,
         return 0;
 }
 
-bool link_dhcp6_pd_is_enabled(Link *link) {
-        if (!link->network)
-                return false;
-
-        return link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_DHCP6;
-}
-
 static bool link_has_preferred_subnet_id(Link *link) {
         if (!link->network)
                 return false;
@@ -607,9 +616,9 @@ static int dhcp6_pd_finalize(Link *link) {
                         link->dhcp6_pd_address_configured = true;
         } else {
                 log_link_debug(link, "Setting DHCPv6 PD addresses");
-                /* address_handler calls link_request_set_routes() and link_request_set_nexthop().
-                 * Before they are called, the related flags must be cleared. Otherwise, the link
-                 * becomes configured state before routes are configured. */
+                /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
+                 * called, the related flags must be cleared. Otherwise, the link becomes configured
+                 * state before routes are configured. */
                 link->static_routes_configured = false;
                 link->static_nexthops_configured = false;
         }
@@ -643,9 +652,6 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) {
                 if (link == dhcp6_link)
                         continue;
 
-                if (!link_dhcp6_pd_is_enabled(link))
-                        continue;
-
                 r = dhcp6_pd_remove(link);
                 if (r < 0)
                         link_enter_failed(link);
@@ -701,7 +707,7 @@ static int dhcp6_remove_old(Link *link, bool force) {
         link_dirty(link);
 
         SET_FOREACH(route, link->dhcp6_routes_old) {
-                k = route_remove(route, link, NULL);
+                k = route_remove(route, NULL, link, NULL);
                 if (k < 0)
                         r = k;
         }
@@ -737,7 +743,7 @@ static int dhcp6_remove(Link *link) {
         link_dirty(link);
 
         SET_FOREACH(route, link->dhcp6_routes) {
-                k = route_remove(route, link, NULL);
+                k = route_remove(route, NULL, link, NULL);
                 if (k < 0)
                         r = k;
         }
@@ -952,7 +958,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
                         return 1;
                 }
 
-                r = link_request_set_routes(link);
+                r = link_set_routes(link);
                 if (r < 0) {
                         link_enter_failed(link);
                         return 1;
@@ -1075,9 +1081,9 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
                 link->dhcp6_address_configured = true;
         else {
                 log_link_debug(link, "Setting DHCPv6 addresses");
-                /* address_handler calls link_request_set_routes() and link_request_set_nexthop().
-                 * Before they are called, the related flags must be cleared. Otherwise, the link
-                 * becomes configured state before routes are configured. */
+                /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
+                 * called, the related flags must be cleared. Otherwise, the link becomes configured
+                 * state before routes are configured. */
                 link->static_routes_configured = false;
                 link->static_nexthops_configured = false;
         }
@@ -1343,17 +1349,51 @@ static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) {
         return false;
 }
 
+static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
+        const DUID *duid;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(client);
+
+        r = sd_dhcp6_client_set_mac(client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER);
+        if (r < 0)
+                return r;
+
+        if (link->network->iaid_set) {
+                r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
+                if (r < 0)
+                        return r;
+        }
+
+        duid = link_get_duid(link);
+        if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
+                r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time);
+        else
+                r = sd_dhcp6_client_set_duid(client,
+                                             duid->type,
+                                             duid->raw_data_len > 0 ? duid->raw_data : NULL,
+                                             duid->raw_data_len);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int dhcp6_configure(Link *link) {
         _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
         sd_dhcp6_option *vendor_option;
         sd_dhcp6_option *send_option;
         void *request_options;
-        const DUID *duid;
         int r;
 
         assert(link);
         assert(link->network);
 
+        if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
+                return 0;
+
         if (link->dhcp6_client)
                 return 0;
 
@@ -1363,32 +1403,13 @@ int dhcp6_configure(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
 
-        r = sd_dhcp6_client_attach_event(client, NULL, 0);
+        r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
 
-        r = sd_dhcp6_client_set_mac(client,
-                                    (const uint8_t *) &link->mac,
-                                    sizeof (link->mac), ARPHRD_ETHER);
-        if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MAC address: %m");
-
-        if (link->network->iaid_set) {
-                r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m");
-        }
-
-        duid = link_get_duid(link);
-        if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
-                r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time);
-        else
-                r = sd_dhcp6_client_set_duid(client,
-                                             duid->type,
-                                             duid->raw_data_len > 0 ? duid->raw_data : NULL,
-                                             duid->raw_data_len);
+        r = dhcp6_set_identifier(link, client);
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
+                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
 
         ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
                 r = sd_dhcp6_client_add_option(client, send_option);
@@ -1406,7 +1427,7 @@ int dhcp6_configure(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
 
-        if (link->network->rapid_commit) {
+        if (link->network->dhcp6_rapid_commit) {
                 r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
                 if (r < 0)
                         return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
@@ -1471,6 +1492,57 @@ int dhcp6_configure(Link *link) {
         return 0;
 }
 
+int dhcp6_update_mac(Link *link) {
+        bool restart;
+        int r;
+
+        assert(link);
+
+        if (!link->dhcp6_client)
+                return 0;
+
+        restart = sd_dhcp6_client_is_running(link->dhcp6_client) > 0;
+
+        if (restart) {
+                r = sd_dhcp6_client_stop(link->dhcp6_client);
+                if (r < 0)
+                        return r;
+        }
+
+        r = dhcp6_set_identifier(link, link->dhcp6_client);
+        if (r < 0)
+                return r;
+
+        if (restart) {
+                r = sd_dhcp6_client_start(link->dhcp6_client);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not restart DHCPv6 client: %m");
+        }
+
+        return 0;
+}
+
+int link_serialize_dhcp6_client(Link *link, FILE *f) {
+        _cleanup_free_ char *duid = NULL;
+        uint32_t iaid;
+        int r;
+
+        assert(link);
+
+        if (!link->dhcp6_client)
+                return 0;
+
+        r = sd_dhcp6_client_get_iaid(link->dhcp6_client, &iaid);
+        if (r >= 0)
+                fprintf(f, "DHCP6_CLIENT_IAID=0x%x\n", iaid);
+
+        r = sd_dhcp6_client_duid_as_string(link->dhcp6_client, &duid);
+        if (r >= 0)
+                fprintf(f, "DHCP6_CLIENT_DUID=%s\n", duid);
+
+        return 0;
+}
+
 int config_parse_dhcp6_pd_hint(
                 const char* unit,
                 const char *filename,
index 214456096da7f9440a3ade1d2ab64bd37ec34640..4956c90915a14657233450cb68a62199ed173f76 100644 (file)
@@ -29,9 +29,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
 bool link_dhcp6_pd_is_enabled(Link *link);
 int dhcp6_pd_remove(Link *link);
 int dhcp6_configure(Link *link);
+int dhcp6_update_mac(Link *link);
 int dhcp6_request_address(Link *link, int ir);
 int dhcp6_request_prefix_delegation(Link *link);
 
+int link_serialize_dhcp6_client(Link *link, FILE *f);
+
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);
index 628c3988accd5db2d1b7f2d6c3c16844179e7e00..2e35f7d1bf525a097699efaeb025c046f95428b0 100644 (file)
@@ -8,27 +8,33 @@
 
 #include "alloc-util.h"
 #include "bridge.h"
-#include "conf-parser.h"
 #include "netlink-util.h"
 #include "networkd-fdb.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
+#include "networkd-network.h"
 #include "parse-util.h"
-#include "string-util.h"
 #include "string-table.h"
-#include "util.h"
 #include "vlan-util.h"
 #include "vxlan.h"
 
 #define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
 
-static const char* const fdb_ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = {
-        [NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use",
-        [NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self",
-        [NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master",
-        [NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router",
-};
+/* remove and FDB entry. */
+FdbEntry *fdb_entry_free(FdbEntry *fdb_entry) {
+        if (!fdb_entry)
+                return NULL;
+
+        if (fdb_entry->network) {
+                assert(fdb_entry->section);
+                hashmap_remove(fdb_entry->network->fdb_entries_by_section, fdb_entry->section);
+        }
+
+        network_config_section_free(fdb_entry->section);
+        return mfree(fdb_entry);
+}
 
-DEFINE_STRING_TABLE_LOOKUP(fdb_ntf_flags, NeighborCacheEntryFlags);
+DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
 
 /* create a new FDB entry or get an existing one. */
 static int fdb_entry_new_static(
@@ -43,23 +49,21 @@ static int fdb_entry_new_static(
 
         assert(network);
         assert(ret);
-        assert(!!filename == (section_line > 0));
-
-        /* search entry in hashmap first. */
-        if (filename) {
-                r = network_config_section_new(filename, section_line, &n);
-                if (r < 0)
-                        return r;
+        assert(filename);
+        assert(section_line > 0);
 
-                fdb_entry = hashmap_get(network->fdb_entries_by_section, n);
-                if (fdb_entry) {
-                        *ret = TAKE_PTR(fdb_entry);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        /* search entry in hashmap first. */
+        fdb_entry = hashmap_get(network->fdb_entries_by_section, n);
+        if (fdb_entry) {
+                *ret = TAKE_PTR(fdb_entry);
+                return 0;
         }
 
-        if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
+        if (hashmap_size(network->fdb_entries_by_section) >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
                 return -E2BIG;
 
         /* allocate space for and FDB entry. */
@@ -70,24 +74,18 @@ static int fdb_entry_new_static(
         /* init FDB structure. */
         *fdb_entry = (FdbEntry) {
                 .network = network,
+                .section = TAKE_PTR(n),
                 .vni = VXLAN_VID_MAX + 1,
                 .fdb_ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
         };
 
-        LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
-        network->n_static_fdb_entries++;
-
-        if (filename) {
-                fdb_entry->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->fdb_entries_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->fdb_entries_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->fdb_entries_by_section, fdb_entry->section, fdb_entry);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->fdb_entries_by_section, fdb_entry->section, fdb_entry);
+        if (r < 0)
+                return r;
 
         /* return allocated FDB structure. */
         *ret = TAKE_PTR(fdb_entry);
@@ -114,7 +112,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
 }
 
 /* send a request to the kernel to add a FDB entry in its static MAC table. */
-int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
+static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -171,22 +169,30 @@ int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
         return 1;
 }
 
-/* remove and FDB entry. */
-void fdb_entry_free(FdbEntry *fdb_entry) {
-        if (!fdb_entry)
-                return;
+int link_set_bridge_fdb(Link *link) {
+        FdbEntry *fdb_entry;
+        int r;
 
-        if (fdb_entry->network) {
-                LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry);
-                assert(fdb_entry->network->n_static_fdb_entries > 0);
-                fdb_entry->network->n_static_fdb_entries--;
+        assert(link);
+        assert(link->network);
 
-                if (fdb_entry->section)
-                        hashmap_remove(fdb_entry->network->fdb_entries_by_section, fdb_entry->section);
+        HASHMAP_FOREACH(fdb_entry, link->network->fdb_entries_by_section) {
+                r = fdb_entry_configure(link, fdb_entry);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
         }
 
-        network_config_section_free(fdb_entry->section);
-        free(fdb_entry);
+        return 0;
+}
+
+void network_drop_invalid_fdb_entries(Network *network) {
+        FdbEntry *fdb_entry;
+
+        assert(network);
+
+        HASHMAP_FOREACH(fdb_entry, network->fdb_entries_by_section)
+                if (section_is_invalid(fdb_entry->section))
+                        fdb_entry_free(fdb_entry);
 }
 
 /* parse the HW address from config files. */
@@ -352,6 +358,15 @@ int config_parse_fdb_vxlan_vni(
         return 0;
 }
 
+static const char* const fdb_ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = {
+        [NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use",
+        [NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self",
+        [NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master",
+        [NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fdb_ntf_flags, NeighborCacheEntryFlags);
+
 int config_parse_fdb_ntf_flags(
                 const char *unit,
                 const char *filename,
index 5e24ad6aee258d342371a7da2748abcf25b75f59..935406e022bd1282f71e4ff4ac7bbf4a09e41c69 100644 (file)
@@ -5,17 +5,16 @@
   Copyright © 2014 Intel Corporation. All rights reserved.
 ***/
 
+#include <inttypes.h>
 #include <linux/neighbour.h>
 
 #include "conf-parser.h"
-#include "list.h"
-#include "macro.h"
+#include "ether-addr-util.h"
+#include "in-addr-util.h"
 #include "networkd-util.h"
 
 typedef struct Network Network;
-typedef struct FdbEntry FdbEntry;
 typedef struct Link Link;
-typedef struct NetworkConfigSection NetworkConfigSection;
 
 typedef enum NeighborCacheEntryFlags {
         NEIGHBOR_CACHE_ENTRY_FLAGS_USE = NTF_USE,
@@ -26,7 +25,7 @@ typedef enum NeighborCacheEntryFlags {
         _NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -1,
 } NeighborCacheEntryFlags;
 
-struct FdbEntry {
+typedef struct FdbEntry {
         Network *network;
         NetworkConfigSection *section;
 
@@ -38,17 +37,13 @@ struct FdbEntry {
         struct ether_addr mac_addr;
         union in_addr_union destination_addr;
         NeighborCacheEntryFlags fdb_ntf_flags;
+} FdbEntry;
 
-        LIST_FIELDS(FdbEntry, static_fdb_entries);
-};
+FdbEntry *fdb_entry_free(FdbEntry *fdb_entry);
 
-void fdb_entry_free(FdbEntry *fdb_entry);
-int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
+void network_drop_invalid_fdb_entries(Network *network);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
-
-const char* fdb_ntf_flags_to_string(NeighborCacheEntryFlags i) _const_;
-NeighborCacheEntryFlags fdb_ntf_flags_from_string(const char *s) _pure_;
+int link_set_bridge_fdb(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
 CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);
index e844799b5735393545d0aa2afde23a823792605d..3be395e1ada6989ef9de339afc85073240660256 100644 (file)
@@ -23,7 +23,7 @@ static int ipv4ll_address_lost(Link *link) {
         if (r < 0)
                 return 0;
 
-        log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
+        log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(addr));
 
         r = address_new(&address);
         if (r < 0)
@@ -79,8 +79,8 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         else if (r < 0)
                 return r;
 
-        log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
-                       ADDRESS_FMT_VAL(address));
+        log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
+                       IPV4_ADDRESS_FMT_VAL(address));
 
         r = address_new(&ll_addr);
         if (r < 0)
@@ -142,23 +142,37 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
         }
 }
 
+static int ipv4ll_init(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (link->ipv4ll)
+                return 0;
+
+        r = sd_ipv4ll_new(&link->ipv4ll);
+        if (r < 0)
+                return r;
+
+        r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int ipv4ll_configure(Link *link) {
         uint64_t seed;
         int r;
 
         assert(link);
-        assert(link->network);
-        assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
 
-        if (!link->ipv4ll) {
-                r = sd_ipv4ll_new(&link->ipv4ll);
-                if (r < 0)
-                        return r;
+        if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
+                return 0;
 
-                r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
-                if (r < 0)
-                        return r;
-        }
+        r = ipv4ll_init(link);
+        if (r < 0)
+                return r;
 
         if (link->sd_device &&
             net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
@@ -182,6 +196,80 @@ int ipv4ll_configure(Link *link) {
         return 0;
 }
 
+int ipv4ll_update_mac(Link *link) {
+        bool restart;
+        int r;
+
+        assert(link);
+
+        if (!link->ipv4ll)
+                return 0;
+
+        restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
+
+        r = sd_ipv4ll_stop(link->ipv4ll);
+        if (r < 0)
+                return r;
+
+        r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
+        if (r < 0)
+                return r;
+
+        if (restart) {
+                r = sd_ipv4ll_start(link->ipv4ll);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int link_serialize_ipv4ll(Link *link, FILE *f) {
+        struct in_addr address;
+        int r;
+
+        assert(link);
+
+        if (!link->ipv4ll)
+                return 0;
+
+        r = sd_ipv4ll_get_address(link->ipv4ll, &address);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return r;
+
+        fputs("IPV4LL_ADDRESS=", f);
+        serialize_in_addrs(f, &address, 1, false, NULL);
+        fputc('\n', f);
+
+        return 0;
+}
+
+int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address) {
+        union in_addr_union address;
+        int r;
+
+        assert(link);
+
+        if (isempty(ipv4ll_address))
+                return 0;
+
+        r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to parse IPv4LL address: %s", ipv4ll_address);
+
+        r = ipv4ll_init(link);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to initialize IPv4LL client: %m");
+
+        r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address);
+
+        return 0;
+}
+
 int config_parse_ipv4ll(
                 const char* unit,
                 const char *filename,
index 49b6fb56ad594b5eaa8ebcbd91fb87c4db4d18ce..4833e304b6c480eafcd48492dbe8f248dd729350 100644 (file)
@@ -8,5 +8,8 @@
 typedef struct Link Link;
 
 int ipv4ll_configure(Link *link);
+int ipv4ll_update_mac(Link *link);
+int link_serialize_ipv4ll(Link *link, FILE *f);
+int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);
index 7051ba9dac4fc05f81cdc4b2ff37208b9d24ec32..fb8464ff2fa7cdeeb3769700f73396fb98d46d10 100644 (file)
@@ -2,9 +2,7 @@
 
 #include <netinet/in.h>
 #include <linux/if.h>
-#include <unistd.h>
 
-#include "fileio.h"
 #include "netlink-util.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-link.h"
 #include "string-util.h"
 #include "sysctl-util.h"
 
+static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(link);
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EEXIST)
+                log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring");
+
+        return 1;
+}
+
+/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
+static int ipv6_proxy_ndp_address_configure(Link *link, const struct in6_addr *address) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(address);
+
+        /* create new netlink message */
+        r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
+
+        r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
+
+        r = sd_netlink_message_append_in6_addr(req, NDA_DST, address);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
+
+        r = netlink_call_async(link->manager->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");
+
+        link_ref(link);
+
+        return 0;
+}
+
 static bool ipv6_proxy_ndp_is_needed(Link *link) {
         assert(link);
 
@@ -26,10 +68,7 @@ static bool ipv6_proxy_ndp_is_needed(Link *link) {
         if (link->network->ipv6_proxy_ndp >= 0)
                 return link->network->ipv6_proxy_ndp;
 
-        if (link->network->n_ipv6_proxy_ndp_addresses == 0)
-                return false;
-
-        return true;
+        return !set_isempty(link->network->ipv6_proxy_ndp_addresses);
 }
 
 static int ipv6_proxy_ndp_set(Link *link) {
@@ -45,47 +84,31 @@ static int ipv6_proxy_ndp_set(Link *link) {
 
         r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
         if (r < 0)
-                log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
+                return log_link_warning_errno(link, r, "Cannot configure proxy NDP for the interface: %m");
 
-        return 0;
+        return v;
 }
 
-static int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
-        _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
-
-        assert(network);
-        assert(ret);
-
-        /* allocate space for IPv6ProxyNDPAddress entry */
-        ipv6_proxy_ndp_address = new(IPv6ProxyNDPAddress, 1);
-        if (!ipv6_proxy_ndp_address)
-                return -ENOMEM;
-
-        *ipv6_proxy_ndp_address = (IPv6ProxyNDPAddress) {
-                .network = network,
-        };
-
-        LIST_PREPEND(ipv6_proxy_ndp_addresses, network->ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address);
-        network->n_ipv6_proxy_ndp_addresses++;
-
-        *ret = TAKE_PTR(ipv6_proxy_ndp_address);
-
-        return 0;
-}
+/* configure all ipv6 proxy ndp addresses */
+int link_set_ipv6_proxy_ndp_addresses(Link *link) {
+        struct in6_addr *address;
+        int r;
 
-void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
-        if (!ipv6_proxy_ndp_address)
-                return;
+        assert(link);
+        assert(link->network);
 
-        if (ipv6_proxy_ndp_address->network) {
-                LIST_REMOVE(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address->network->ipv6_proxy_ndp_addresses,
-                            ipv6_proxy_ndp_address);
+        /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
+        r = ipv6_proxy_ndp_set(link);
+        if (r <= 0)
+                return r;
 
-                assert(ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses > 0);
-                ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses--;
+        SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) {
+                r = ipv6_proxy_ndp_address_configure(link, address);
+                if (r < 0)
+                        return r;
         }
 
-        free(ipv6_proxy_ndp_address);
+        return 0;
 }
 
 int config_parse_ipv6_proxy_ndp_address(
@@ -100,26 +123,24 @@ int config_parse_ipv6_proxy_ndp_address(
                 void *data,
                 void *userdata) {
 
+        _cleanup_free_ struct in6_addr *address = NULL;
         Network *network = userdata;
-        _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
-        int r;
         union in_addr_union buffer;
+        int r;
 
         assert(filename);
-        assert(section);
-        assert(lvalue);
         assert(rvalue);
-        assert(data);
+        assert(network);
 
-        r = ipv6_proxy_ndp_address_new_static(network, &ipv6_proxy_ndp_address);
-        if (r < 0)
-                return log_oom();
+        if (isempty(rvalue)) {
+                network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
+                return 0;
+        }
 
         r = in_addr_from_string(AF_INET6, rvalue, &buffer);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse IPv6 proxy NDP address, ignoring: %s",
-                           rvalue);
+                           "Failed to parse IPv6 proxy NDP address, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -129,76 +150,15 @@ int config_parse_ipv6_proxy_ndp_address(
                 return 0;
         }
 
-        ipv6_proxy_ndp_address->in_addr = buffer.in6;
-        ipv6_proxy_ndp_address = NULL;
-
-        return 0;
-}
-
-static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        int r;
-
-        assert(link);
-
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST)
-                log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring");
-
-        return 1;
-}
-
-/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
-int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        sd_netlink *rtnl;
-        int r;
-
-        assert(link);
-        assert(link->network);
-        assert(link->manager);
-        assert(ipv6_proxy_ndp_address);
-
-        rtnl = link->manager->rtnl;
-
-        /* create new netlink message */
-        r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
-
-        r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
-
-        r = sd_netlink_message_append_in6_addr(req, NDA_DST, &ipv6_proxy_ndp_address->in_addr);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
+        address = newdup(struct in6_addr, &buffer.in6, 1);
+        if (!address)
+                return log_oom();
 
-        r = netlink_call_async(rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler,
-                               link_netlink_destroy_callback, link);
+        r = set_ensure_put(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops, address);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
-        link_ref(link);
-
-        return 0;
-}
-
-/* configure all ipv6 proxy ndp addresses */
-int ipv6_proxy_ndp_addresses_configure(Link *link) {
-        IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
-        int r;
-
-        assert(link);
-
-        /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
-        r = ipv6_proxy_ndp_set(link);
-        if (r != 0)
-                return r;
+                return log_oom();
+        if (r > 0)
+                TAKE_PTR(address);
 
-        LIST_FOREACH(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address, link->network->ipv6_proxy_ndp_addresses) {
-                r = ipv6_proxy_ndp_address_configure(link, ipv6_proxy_ndp_address);
-                if (r != 0)
-                        return r;
-        }
         return 0;
 }
index d6666beab5ce76eeec9eb26b013b38977bb2a367..e58b17ec942585fe0dc96fd3fd0bcad33f39c509 100644 (file)
@@ -2,24 +2,9 @@
 #pragma once
 
 #include "conf-parser.h"
-#include "list.h"
-#include "macro.h"
 
-typedef struct Network Network;
-typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
 typedef struct Link Link;
 
-struct IPv6ProxyNDPAddress {
-        Network *network;
-        struct in6_addr in_addr;
-
-        LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
-};
-
-void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
-int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
-int ipv6_proxy_ndp_addresses_configure(Link *link);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6ProxyNDPAddress*, ipv6_proxy_ndp_address_free);
+int link_set_ipv6_proxy_ndp_addresses(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address);
index 0cdd2b5121e064b7a61141cc8b2ee9ba8524a3f1..faf74bd8393c67a6734ae3f8e67e7dda474bf52c 100644 (file)
 #include "missing_network.h"
 #include "netlink-util.h"
 #include "network-internal.h"
+#include "networkd-address-label.h"
+#include "networkd-address.h"
 #include "networkd-can.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-dhcp4.h"
 #include "networkd-dhcp6.h"
+#include "networkd-fdb.h"
 #include "networkd-ipv4ll.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-link-bus.h"
 #include "networkd-link.h"
 #include "networkd-lldp-tx.h"
 #include "networkd-manager.h"
+#include "networkd-mdb.h"
 #include "networkd-ndisc.h"
 #include "networkd-neighbor.h"
+#include "networkd-nexthop.h"
 #include "networkd-sriov.h"
+#include "networkd-sysctl.h"
 #include "networkd-radv.h"
 #include "networkd-routing-policy-rule.h"
 #include "networkd-wifi.h"
 #include "util.h"
 #include "vrf.h"
 
-uint32_t link_get_vrf_table(Link *link) {
-        return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
-}
-
-uint32_t link_get_dhcp_route_table(Link *link) {
-        /* When the interface is part of an VRF use the VRFs routing table, unless
-         * another table is explicitly specified. */
-        if (link->network->dhcp_route_table_set)
-                return link->network->dhcp_route_table;
-        return link_get_vrf_table(link);
-}
-
-uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
-        if (link->network->ipv6_accept_ra_route_table_set)
-                return link->network->ipv6_accept_ra_route_table;
-        return link_get_vrf_table(link);
-}
-
-DUID* link_get_duid(Link *link) {
-        if (link->network->duid.type != _DUID_TYPE_INVALID)
-                return &link->network->duid;
-        else
-                return &link->manager->duid;
-}
-
-static bool link_dhcp6_enabled(Link *link) {
-        assert(link);
-
-        if (!socket_ipv6_is_supported())
-                return false;
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->bond)
-                return false;
-
-        if (link->iftype == ARPHRD_CAN)
-                return false;
-
-        return link->network->dhcp & ADDRESS_FAMILY_IPV6;
-}
-
-static bool link_dhcp4_enabled(Link *link) {
-        assert(link);
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->bond)
-                return false;
-
-        if (link->iftype == ARPHRD_CAN)
-                return false;
-
-        return link->network->dhcp & ADDRESS_FAMILY_IPV4;
-}
-
-static bool link_dhcp4_server_enabled(Link *link) {
-        assert(link);
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->bond)
-                return false;
-
-        if (link->iftype == ARPHRD_CAN)
-                return false;
-
-        return link->network->dhcp_server;
-}
-
 bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
         assert(link);
         assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
@@ -159,7 +83,7 @@ bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
         return link->network->link_local & mask;
 }
 
-static bool link_ipv6ll_enabled(Link *link) {
+bool link_ipv6ll_enabled(Link *link) {
         assert(link);
 
         if (!socket_ipv6_is_supported())
@@ -183,7 +107,7 @@ static bool link_ipv6ll_enabled(Link *link) {
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
 }
 
-static bool link_ipv6_enabled(Link *link) {
+bool link_ipv6_enabled(Link *link) {
         assert(link);
 
         if (!socket_ipv6_is_supported())
@@ -205,127 +129,6 @@ static bool link_ipv6_enabled(Link *link) {
         return false;
 }
 
-static bool link_radv_enabled(Link *link) {
-        assert(link);
-
-        if (!link_ipv6ll_enabled(link))
-                return false;
-
-        return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
-}
-
-static bool link_ipv4_forward_enabled(Link *link) {
-        assert(link);
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
-                return false;
-
-        return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
-}
-
-static bool link_ipv6_forward_enabled(Link *link) {
-        assert(link);
-
-        if (!socket_ipv6_is_supported())
-                return false;
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
-                return false;
-
-        return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
-}
-
-static bool link_proxy_arp_enabled(Link *link) {
-        assert(link);
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (link->network->proxy_arp < 0)
-                return false;
-
-        return true;
-}
-
-static bool link_ipv6_accept_ra_enabled(Link *link) {
-        assert(link);
-
-        if (!socket_ipv6_is_supported())
-                return false;
-
-        if (link->flags & IFF_LOOPBACK)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (!link_ipv6ll_enabled(link))
-                return false;
-
-        /* If unset use system default (enabled if local forwarding is disabled.
-         * disabled if local forwarding is enabled).
-         * If set, ignore or enforce RA independent of local forwarding state.
-         */
-        if (link->network->ipv6_accept_ra < 0)
-                /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
-                return !link_ipv6_forward_enabled(link);
-        else if (link->network->ipv6_accept_ra > 0)
-                /* accept RA even if ip_forward is enabled */
-                return true;
-        else
-                /* ignore RA */
-                return false;
-}
-
-static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
-        assert(link);
-
-        if (!socket_ipv6_is_supported())
-                return _IPV6_PRIVACY_EXTENSIONS_INVALID;
-
-        if (link->flags & IFF_LOOPBACK)
-                return _IPV6_PRIVACY_EXTENSIONS_INVALID;
-
-        if (!link->network)
-                return _IPV6_PRIVACY_EXTENSIONS_INVALID;
-
-        return link->network->ipv6_privacy_extensions;
-}
-
-static int link_update_ipv6_sysctl(Link *link) {
-        bool enabled;
-        int r;
-
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        enabled = link_ipv6_enabled(link);
-        if (enabled) {
-                r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Cannot enable IPv6: %m");
-
-                log_link_info(link, "IPv6 successfully enabled");
-        }
-
-        return 0;
-}
-
 static bool link_is_enslaved(Link *link) {
         if (link->flags & IFF_SLAVE)
                 /* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */
@@ -690,8 +493,10 @@ static void link_free_engines(Link *link) {
         link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
         link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
+        link->dhcp_acd = sd_ipv4acd_unref(link->dhcp_acd);
 
         link->lldp = sd_lldp_unref(link->lldp);
+        link_lldp_emit_stop(link);
 
         ndisc_flush(link);
 
@@ -700,11 +505,11 @@ static void link_free_engines(Link *link) {
         link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
         link->ndisc = sd_ndisc_unref(link->ndisc);
         link->radv = sd_radv_unref(link->radv);
+
+        ipv4_dad_unref(link);
 }
 
 static Link *link_free(Link *link) {
-        Address *address;
-
         assert(link);
 
         link_ntp_settings_clear(link);
@@ -728,6 +533,7 @@ static Link *link_free(Link *link) {
 
         link->addresses = set_free(link->addresses);
         link->addresses_foreign = set_free(link->addresses_foreign);
+        link->pool_addresses = set_free(link->pool_addresses);
         link->static_addresses = set_free(link->static_addresses);
         link->dhcp6_addresses = set_free(link->dhcp6_addresses);
         link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old);
@@ -735,12 +541,6 @@ static Link *link_free(Link *link) {
         link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
         link->ndisc_addresses = set_free(link->ndisc_addresses);
 
-        while ((address = link->pool_addresses)) {
-                LIST_REMOVE(addresses, link->pool_addresses, address);
-                address_free(address);
-        }
-
-        link_lldp_emit_stop(link);
         link_free_engines(link);
         free(link->lease_file);
         free(link->lldp_file);
@@ -807,9 +607,8 @@ static void link_enter_unmanaged(Link *link) {
         link_dirty(link);
 }
 
-int link_stop_clients(Link *link, bool may_keep_dhcp) {
+int link_stop_engines(Link *link, bool may_keep_dhcp) {
         int r = 0, k;
-        Address *ad;
 
         assert(link);
         assert(link->manager);
@@ -820,49 +619,47 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
                          (link->manager->restarting ||
                           FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
 
-        if (link->dhcp_client && !keep_dhcp) {
+        if (!keep_dhcp) {
                 k = sd_dhcp_client_stop(link->dhcp_client);
                 if (k < 0)
                         r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
         }
 
-        if (link->ipv4ll) {
-                k = sd_ipv4ll_stop(link->ipv4ll);
-                if (k < 0)
-                        r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
-        }
+        k = sd_ipv4acd_stop(link->dhcp_acd);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client for DHCPv4: %m");
 
-        if (link->network)
-                LIST_FOREACH(addresses, ad, link->network->static_addresses)
-                        if (ad->acd && sd_ipv4acd_is_running(ad->acd) == 0) {
-                                k = sd_ipv4acd_stop(ad->acd);
-                                if (k < 0)
-                                        r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
-                        }
+        k = sd_dhcp_server_stop(link->dhcp_server);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop DHCPv4 server: %m");
 
-        if (link->dhcp6_client) {
-                k = sd_dhcp6_client_stop(link->dhcp6_client);
-                if (k < 0)
-                        r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
-        }
+        k = sd_lldp_stop(link->lldp);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop LLDP: %m");
 
-        if (link_dhcp6_pd_is_enabled(link)) {
-                k = dhcp6_pd_remove(link);
-                if (k < 0)
-                        r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
-        }
+        k = sd_ipv4ll_stop(link->ipv4ll);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
 
-        if (link->ndisc) {
-                k = sd_ndisc_stop(link->ndisc);
-                if (k < 0)
-                        r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
-        }
+        k = ipv4_dad_stop(link);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
 
-        if (link->radv) {
-                k = sd_radv_stop(link->radv);
-                if (k < 0)
-                        r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
-        }
+        k = sd_dhcp6_client_stop(link->dhcp6_client);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
+
+        k = dhcp6_pd_remove(link);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
+
+        k = sd_ndisc_stop(link->ndisc);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
+
+        k = sd_radv_stop(link->radv);
+        if (k < 0)
+                r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
 
         link_lldp_emit_stop(link);
         return r;
@@ -878,7 +675,7 @@ void link_enter_failed(Link *link) {
 
         link_set_state(link, LINK_STATE_FAILED);
 
-        link_stop_clients(link, false);
+        (void) link_stop_engines(link, false);
 
         link_dirty(link);
 }
@@ -925,251 +722,79 @@ static void link_enter_configured(Link *link) {
         link_dirty(link);
 }
 
-static int link_request_set_routing_policy_rule(Link *link) {
-        RoutingPolicyRule *rule, *rrule = NULL;
-        int r;
+void link_check_ready(Link *link) {
+        Address *a;
 
         assert(link);
-        assert(link->network);
-
-        link->routing_policy_rules_configured = false;
-
-        LIST_FOREACH(rules, rule, link->network->rules) {
-                r = routing_policy_rule_get(link->manager, rule, &rrule);
-                if (r >= 0) {
-                        if (r == 0)
-                                (void) routing_policy_rule_make_local(link->manager, rrule);
-                        continue;
-                }
 
-                r = routing_policy_rule_configure(rule, link, NULL);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
-                if (r > 0)
-                        link->routing_policy_rule_messages++;
-        }
+        if (link->state == LINK_STATE_CONFIGURED)
+                return;
 
-        routing_policy_rule_purge(link->manager, link);
-        if (link->routing_policy_rule_messages == 0)
-                link->routing_policy_rules_configured = true;
-        else {
-                log_link_debug(link, "Setting routing policy rules");
-                link_set_state(link, LINK_STATE_CONFIGURING);
+        if (link->state != LINK_STATE_CONFIGURING) {
+                log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
+                return;
         }
 
-        return 0;
-}
+        if (!link->network)
+                return;
 
-static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        int r;
+        if (!link->addresses_configured) {
+                log_link_debug(link, "%s(): static addresses are not configured.", __func__);
+                return;
+        }
 
-        assert(link);
-        assert(link->nexthop_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
-                      LINK_STATE_FAILED, LINK_STATE_LINGER));
+        if (!link->neighbors_configured) {
+                log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
+                return;
+        }
 
-        link->nexthop_messages--;
+        SET_FOREACH(a, link->addresses)
+                if (!address_is_ready(a)) {
+                        _cleanup_free_ char *str = NULL;
 
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
+                        (void) in_addr_to_string(a->family, &a->in_addr, &str);
+                        log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
+                        return;
+                }
 
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST) {
-                log_link_message_warning_errno(link, m, r, "Could not set nexthop");
-                link_enter_failed(link);
-                return 1;
+        if (!link->static_routes_configured) {
+                log_link_debug(link, "%s(): static routes are not configured.", __func__);
+                return;
         }
 
-        if (link->nexthop_messages == 0) {
-                log_link_debug(link, "Nexthop set");
-                link->static_nexthops_configured = true;
-                link_check_ready(link);
+        if (!link->static_nexthops_configured) {
+                log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
+                return;
         }
 
-        return 1;
-}
-
-static int link_request_set_nexthop(Link *link) {
-        NextHop *nh;
-        int r;
+        if (!link->routing_policy_rules_configured) {
+                log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
+                return;
+        }
 
-        link->static_nexthops_configured = false;
+        if (!link->tc_configured) {
+                log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
+                return;
+        }
 
-        LIST_FOREACH(nexthops, nh, link->network->static_nexthops) {
-                r = nexthop_configure(nh, link, nexthop_handler);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not set nexthop: %m");
-                if (r > 0)
-                        link->nexthop_messages++;
+        if (!link->sr_iov_configured) {
+                log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
+                return;
         }
 
-        if (link->nexthop_messages == 0) {
-                link->static_nexthops_configured = true;
-                link_check_ready(link);
-        } else {
-                log_link_debug(link, "Setting nexthop");
-                link_set_state(link, LINK_STATE_CONFIGURING);
+        if (!link->bridge_mdb_configured) {
+                log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
+                return;
         }
 
-        return 1;
-}
+        if (link_has_carrier(link) || !link->network->configure_without_carrier) {
+                bool has_ndisc_address = false;
+                NDiscAddress *n;
 
-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_CONFIGURING,
-                      LINK_STATE_FAILED, LINK_STATE_LINGER));
-
-        link->route_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_message_warning_errno(link, m, r, "Could not set route");
-                link_enter_failed(link);
-                return 1;
-        }
-
-        if (link->route_messages == 0) {
-                log_link_debug(link, "Routes set");
-                link->static_routes_configured = true;
-                link_request_set_nexthop(link);
-        }
-
-        return 1;
-}
-
-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 */
-                _PHASE_MAX
-        } phase;
-        Route *rt;
-        int r;
-
-        assert(link);
-        assert(link->network);
-        assert(link->state != _LINK_STATE_INVALID);
-
-        link->static_routes_configured = false;
-
-        if (!link->addresses_ready)
-                return 0;
-
-        if (!link_has_carrier(link) && !link->network->configure_without_carrier)
-                /* During configuring addresses, the link lost its carrier. As networkd is dropping
-                 * the addresses now, let's not configure the routes either. */
-                return 0;
-
-        r = link_request_set_routing_policy_rule(link);
-        if (r < 0)
-                return r;
-
-        /* 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++)
-                LIST_FOREACH(routes, rt, link->network->static_routes) {
-                        if (rt->gateway_from_dhcp)
-                                continue;
-
-                        if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
-                                continue;
-
-                        r = route_configure(rt, link, route_handler, NULL);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not set routes: %m");
-                        if (r > 0)
-                                link->route_messages++;
-                }
-
-        if (link->route_messages == 0) {
-                link->static_routes_configured = true;
-                link_request_set_nexthop(link);
-        } else {
-                log_link_debug(link, "Setting routes");
-                link_set_state(link, LINK_STATE_CONFIGURING);
-        }
-
-        return 0;
-}
-
-void link_check_ready(Link *link) {
-        Address *a;
-
-        assert(link);
-
-        if (link->state == LINK_STATE_CONFIGURED)
-                return;
-
-        if (link->state != LINK_STATE_CONFIGURING) {
-                log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
-                return;
-        }
-
-        if (!link->network)
-                return;
-
-        if (!link->addresses_configured) {
-                log_link_debug(link, "%s(): static addresses are not configured.", __func__);
-                return;
-        }
-
-        if (!link->neighbors_configured) {
-                log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
-                return;
-        }
-
-        SET_FOREACH(a, link->addresses)
-                if (!address_is_ready(a)) {
-                        _cleanup_free_ char *str = NULL;
-
-                        (void) in_addr_to_string(a->family, &a->in_addr, &str);
-                        log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
-                        return;
-                }
-
-        if (!link->static_routes_configured) {
-                log_link_debug(link, "%s(): static routes are not configured.", __func__);
-                return;
-        }
-
-        if (!link->static_nexthops_configured) {
-                log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
-                return;
-        }
-
-        if (!link->routing_policy_rules_configured) {
-                log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
-                return;
-        }
-
-        if (!link->tc_configured) {
-                log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
-                return;
-        }
-
-        if (!link->sr_iov_configured) {
-                log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
-                return;
-        }
-
-        if (!link->bridge_mdb_configured) {
-                log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
-                return;
-        }
-
-        if (link_has_carrier(link) || !link->network->configure_without_carrier) {
-                bool has_ndisc_address = false;
-                NDiscAddress *n;
-
-                if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
-                        log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
-                        return;
-                }
+                if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
+                        log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
+                        return;
+                }
 
                 if (link_ipv6ll_enabled(link) &&
                     in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
@@ -1219,290 +844,162 @@ void link_check_ready(Link *link) {
         return;
 }
 
-static int link_request_set_neighbors(Link *link) {
-        Neighbor *neighbor;
+static int link_set_static_configs(Link *link) {
         int r;
 
         assert(link);
         assert(link->network);
         assert(link->state != _LINK_STATE_INVALID);
 
+        /* Reset all *_configured flags we are configuring. */
+        link->request_static_addresses = false;
+        link->addresses_configured = false;
+        link->addresses_ready = false;
         link->neighbors_configured = false;
+        link->static_routes_configured = false;
+        link->static_nexthops_configured = false;
+        link->routing_policy_rules_configured = false;
 
-        LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
-                r = neighbor_configure(neighbor, link, NULL);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not set neighbor: %m");
-        }
+        r = link_set_bridge_fdb(link);
+        if (r < 0)
+                return r;
 
-        if (link->neighbor_messages == 0) {
-                link->neighbors_configured = true;
-                link_check_ready(link);
-        } else {
-                log_link_debug(link, "Setting neighbors");
-                link_set_state(link, LINK_STATE_CONFIGURING);
-        }
+        r = link_set_bridge_mdb(link);
+        if (r < 0)
+                return r;
 
-        return 0;
-}
+        r = link_set_neighbors(link);
+        if (r < 0)
+                return r;
 
-static int link_set_bridge_fdb(Link *link) {
-        FdbEntry *fdb_entry;
-        int r;
+        r = link_set_addresses(link);
+        if (r < 0)
+                return r;
 
-        LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
-                r = fdb_entry_configure(link, fdb_entry);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
-        }
+        r = link_set_address_labels(link);
+        if (r < 0)
+                return r;
+
+        /* now that we can figure out a default address for the dhcp server, start it */
+        r = dhcp4_server_configure(link);
+        if (r < 0)
+                return r;
 
         return 0;
 }
 
-static int static_address_ready_callback(Address *address) {
-        Address *a;
-        Link *link;
-
-        assert(address);
-        assert(address->link);
-
-        link = address->link;
-
-        if (!link->addresses_configured)
-                return 0;
+static int link_configure_continue(Link *link);
 
-        SET_FOREACH(a, link->static_addresses)
-                if (!address_is_ready(a)) {
-                        _cleanup_free_ char *str = NULL;
+static int link_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
 
-                        (void) in_addr_to_string(a->family, &a->in_addr, &str);
-                        log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
-                        return 0;
-                }
+        assert(link);
 
-        /* This should not be called again */
-        SET_FOREACH(a, link->static_addresses)
-                a->callback = NULL;
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
 
-        link->addresses_ready = true;
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0)
+                log_link_message_warning_errno(link, m, r, "Could not set MAC address, ignoring");
+        else
+                log_link_debug(link, "Setting MAC address done.");
 
-        return link_request_set_routes(link);
+        return 1;
 }
 
-static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int link_set_mac(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
-        assert(rtnl);
-        assert(m);
         assert(link);
-        assert(link->ifname);
-        assert(link->address_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
-               LINK_STATE_FAILED, LINK_STATE_LINGER));
+        assert(link->network);
+        assert(link->manager);
+        assert(link->manager->rtnl);
 
-        link->address_messages--;
+        if (!link->network->mac)
+                return 0;
 
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
+        log_link_debug(link, "Setting MAC address");
 
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST) {
-                log_link_message_warning_errno(link, m, r, "Could not set address");
-                link_enter_failed(link);
-                return 1;
-        } else if (r >= 0)
-                (void) manager_rtnl_process_address(rtnl, m, link->manager);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        if (link->address_messages == 0) {
-                Address *a;
+        r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not set MAC address: %m");
 
-                log_link_debug(link, "Addresses set");
-                link->addresses_configured = true;
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_mac_handler,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
-                /* When all static addresses are already ready, then static_address_ready_callback()
-                 * will not be called automatically. So, call it here. */
-                a = set_first(link->static_addresses);
-                if (!a) {
-                        log_link_warning(link, "No static address is stored.");
-                        link_enter_failed(link);
-                        return 1;
-                }
-                if (!a->callback) {
-                        log_link_warning(link, "Address ready callback is not set.");
-                        link_enter_failed(link);
-                        return 1;
-                }
-                r = a->callback(a);
-                if (r < 0)
-                        link_enter_failed(link);
-        }
+        link_ref(link);
 
-        return 1;
+        return 0;
 }
 
-static int static_address_configure(Address *address, Link *link, bool update) {
-        Address *ret;
+static int link_nomaster_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
-        assert(address);
         assert(link);
 
-        r = address_configure(address, link, address_handler, update, &ret);
-        if (r < 0)
-                return log_link_warning_errno(link, r, "Could not configure static address: %m");
-
-        link->address_messages++;
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
 
-        r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0)
-                return log_link_warning_errno(link, r, "Failed to store static address: %m");
-
-        ret->callback = static_address_ready_callback;
+                log_link_message_warning_errno(link, m, r, "Could not set nomaster, ignoring");
+        else
+                log_link_debug(link, "Setting nomaster done.");
 
-        return 0;
+        return 1;
 }
 
-static int link_request_set_addresses(Link *link) {
-        AddressLabel *label;
-        Address *ad;
-        Prefix *p;
+static int link_set_nomaster(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
         assert(link->network);
-        assert(link->state != _LINK_STATE_INVALID);
+        assert(link->manager);
+        assert(link->manager->rtnl);
 
-        if (link->address_remove_messages != 0) {
-                log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
-                link->request_static_addresses = true;
+        /* set it free if not enslaved with networkd */
+        if (link->network->bridge || link->network->bond || link->network->vrf)
                 return 0;
-        }
 
-        /* Reset all *_configured flags we are configuring. */
-        link->request_static_addresses = false;
-        link->addresses_configured = false;
-        link->addresses_ready = false;
-        link->neighbors_configured = false;
-        link->static_routes_configured = false;
-        link->static_nexthops_configured = false;
-        link->routing_policy_rules_configured = false;
+        log_link_debug(link, "Setting nomaster");
 
-        r = link_set_bridge_fdb(link);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
         if (r < 0)
-                return r;
+                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        r = link_set_bridge_mdb(link);
+        r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0);
         if (r < 0)
-                return r;
+                return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m");
 
-        r = link_request_set_neighbors(link);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_nomaster_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
-                return r;
-
-        LIST_FOREACH(addresses, ad, link->network->static_addresses) {
-                bool update;
-
-                if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
-                        update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
-                else
-                        update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
-                r = static_address_configure(ad, link, update);
-                if (r < 0)
-                        return r;
-        }
+        link_ref(link);
 
-        if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC)
-                LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
-                        _cleanup_(address_freep) Address *address = NULL;
+        return 0;
+}
 
-                        if (!p->assign)
-                                continue;
+static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
 
-                        r = address_new(&address);
-                        if (r < 0)
-                                return log_oom();
+        assert(m);
+        assert(link);
+        assert(link->ifname);
 
-                        r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
+        link->setting_mtu = false;
 
-                        r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
-
-                        address->family = AF_INET6;
-                        r = static_address_configure(address, link, true);
-                        if (r < 0)
-                                return r;
-                }
-
-        LIST_FOREACH(labels, label, link->network->address_labels) {
-                r = address_label_configure(label, link, NULL, false);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not set address label: %m");
-
-                link->address_label_messages++;
-        }
-
-        /* now that we can figure out a default address for the dhcp server, start it */
-        if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) {
-                r = dhcp4_server_configure(link);
-                if (r < 0)
-                        return r;
-                log_link_debug(link, "Offering DHCPv4 leases");
-        }
-
-        if (link->address_messages == 0) {
-                link->addresses_configured = true;
-                link->addresses_ready = true;
-                r = link_request_set_routes(link);
-                if (r < 0)
-                        return r;
-        } else {
-                log_link_debug(link, "Setting addresses");
-                link_set_state(link, LINK_STATE_CONFIGURING);
-        }
-
-        return 0;
-}
-
-static int link_set_bridge_vlan(Link *link) {
-        int r;
-
-        r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
-        if (r < 0)
-                log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m");
-
-        return r;
-}
-
-static int link_set_proxy_arp(Link *link) {
-        int r;
-
-        if (!link_proxy_arp_enabled(link))
-                return 0;
-
-        r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
-        if (r < 0)
-                log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
-
-        return 0;
-}
-
-static int link_configure_continue(Link *link);
-
-static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        int r;
-
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-
-        link->setting_mtu = false;
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0)
@@ -1679,9 +1176,7 @@ static int link_acquire_ipv6_conf(Link *link) {
 
         assert(link);
 
-        if (link_ipv6_accept_ra_enabled(link)) {
-                assert(link->ndisc);
-
+        if (link->ndisc) {
                 log_link_debug(link, "Discovering IPv6 routers");
 
                 r = sd_ndisc_start(link->ndisc);
@@ -1689,7 +1184,7 @@ static int link_acquire_ipv6_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
         }
 
-        if (link_radv_enabled(link)) {
+        if (link->radv) {
                 assert(link->radv);
                 assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
 
@@ -1741,9 +1236,7 @@ static int link_acquire_ipv4_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
         }
 
-        if (link_dhcp4_enabled(link)) {
-                assert(link->dhcp_client);
-
+        if (link->dhcp_client) {
                 log_link_debug(link, "Acquiring DHCPv4 lease");
 
                 r = sd_dhcp_client_start(link->dhcp_client);
@@ -1769,11 +1262,9 @@ static int link_acquire_conf(Link *link) {
                         return r;
         }
 
-        if (link_lldp_emit_enabled(link)) {
-                r = link_lldp_emit_start(link);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
-        }
+        r = link_lldp_emit_start(link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
 
         return 0;
 }
@@ -1914,23 +1405,10 @@ static int link_up(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        /* set it free if not enslaved with networkd */
-        if (!link->network->bridge && !link->network->bond && !link->network->vrf) {
-                r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m");
-        }
-
         r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        if (link->network->mac) {
-                r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set MAC address: %m");
-        }
-
         r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
@@ -2362,12 +1840,9 @@ static int link_joined(Link *link) {
                         log_link_error_errno(link, r, "Failed to add to bond master's slave list: %m");
         }
 
-        if (link->network->use_br_vlan &&
-            (link->network->bridge || streq_ptr("bridge", link->kind))) {
-                r = link_set_bridge_vlan(link);
-                if (r < 0)
-                        log_link_error_errno(link, r, "Could not set bridge vlan: %m");
-        }
+        r = link_set_bridge_vlan(link);
+        if (r < 0)
+                log_link_error_errno(link, r, "Could not set bridge vlan: %m");
 
         /* Skip setting up addresses until it gets carrier,
            or it would try to set addresses twice,
@@ -2376,7 +1851,12 @@ static int link_joined(Link *link) {
                 return 0;
 
         link_set_state(link, LINK_STATE_CONFIGURING);
-        return link_request_set_addresses(link);
+
+        r = link_acquire_conf(link);
+        if (r < 0)
+                return r;
+
+        return link_set_static_configs(link);
 }
 
 static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@@ -2516,519 +1996,41 @@ static int link_enter_join_netdev(Link *link) {
         return 0;
 }
 
-static int link_set_ipv4_forward(Link *link) {
-        int r;
-
-        if (!link_ipv4_forward_enabled(link))
-                return 0;
-
-        /* We propagate the forwarding flag from one interface to the
-         * global setting one way. This means: as long as at least one
-         * interface was configured at any time that had IP forwarding
-         * enabled the setting will stay on for good. We do this
-         * primarily to keep IPv4 and IPv6 packet forwarding behaviour
-         * somewhat in sync (see below). */
-
-        r = sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
-        if (r < 0)
-                log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_forward(Link *link) {
-        int r;
-
-        if (!link_ipv6_forward_enabled(link))
-                return 0;
-
-        /* On Linux, the IPv6 stack does not know a per-interface
-         * packet forwarding setting: either packet forwarding is on
-         * for all, or off for all. We hence don't bother with a
-         * per-interface setting, but simply propagate the interface
-         * flag, if it is set, to the global flag, one-way. Note that
-         * while IPv4 would allow a per-interface flag, we expose the
-         * same behaviour there and also propagate the setting from
-         * one to all, to keep things simple (see above). */
-
-        r = sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
-        if (r < 0)
-                log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_privacy_extensions(Link *link) {
-        IPv6PrivacyExtensions s;
-        int r;
-
-        s = link_ipv6_privacy_extensions(link);
-        if (s < 0)
-                return 0;
-
-        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) link->network->ipv6_privacy_extensions);
-        if (r < 0)
-                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_accept_ra(Link *link) {
-        int r;
-
-        /* Make this a NOP if IPv6 is not available */
-        if (!socket_ipv6_is_supported())
-                return 0;
-
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        if (!link->network)
-                return 0;
-
-        r = sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
-        if (r < 0)
-                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_dad_transmits(Link *link) {
+static int link_drop_foreign_config(Link *link) {
         int r;
 
-        /* Make this a NOP if IPv6 is not available */
-        if (!socket_ipv6_is_supported())
-                return 0;
-
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        if (!link->network)
-                return 0;
-
-        if (link->network->ipv6_dad_transmits < 0)
-                return 0;
-
-        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
+        r = link_drop_foreign_addresses(link);
         if (r < 0)
-                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_hop_limit(Link *link) {
-        int r;
-
-        /* Make this a NOP if IPv6 is not available */
-        if (!socket_ipv6_is_supported())
-                return 0;
-
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        if (!link->network)
-                return 0;
-
-        if (link->network->ipv6_hop_limit < 0)
-                return 0;
+                return r;
 
-        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
+        r = link_drop_foreign_neighbors(link);
         if (r < 0)
-                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
-
-        return 0;
-}
-
-static int link_set_ipv6_mtu(Link *link) {
-        int r;
-
-        /* Make this a NOP if IPv6 is not available */
-        if (!socket_ipv6_is_supported())
-                return 0;
-
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        if (link->network->ipv6_mtu == 0)
-                return 0;
-
-        /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
-         * on the interface. Bump up IPv6 MTU bytes to IPV6_MTU_MIN. */
-        if (link->network->ipv6_mtu < IPV6_MIN_MTU) {
-                log_link_notice(link, "Bumping IPv6 MTU to "STRINGIFY(IPV6_MIN_MTU)" byte minimum required");
-                link->network->ipv6_mtu = IPV6_MIN_MTU;
-        }
-
-        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
-        if (r < 0) {
-                if (link->mtu < link->network->ipv6_mtu)
-                        log_link_warning(link, "Cannot set IPv6 MTU %"PRIu32" higher than device MTU %"PRIu32,
-                                         link->network->ipv6_mtu, link->mtu);
-                else
-                        log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m");
-        }
-
-        link->ipv6_mtu_set = true;
+                return r;
 
-        return 0;
+        return link_drop_foreign_routes(link);
 }
 
-static int link_set_ipv4_accept_local(Link *link) {
+static int link_drop_config(Link *link) {
         int r;
 
-        if (link->flags & IFF_LOOPBACK)
-                return 0;
-
-        if (link->network->ipv4_accept_local < 0)
-                return 0;
-
-        r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local);
+        r = link_drop_addresses(link);
         if (r < 0)
-                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface: %m");
-
-        return 0;
-}
-
-static bool link_is_static_address_configured(Link *link, Address *address) {
-        Address *net_address;
-
-        assert(link);
-        assert(address);
-
-        if (!link->network)
-                return false;
-
-        LIST_FOREACH(addresses, net_address, link->network->static_addresses)
-                if (address_equal(net_address, address))
-                        return true;
-                else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
-                         in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
-                        return true;
-
-        return false;
-}
-
-static bool link_is_neighbor_configured(Link *link, Neighbor *neighbor) {
-        Neighbor *net_neighbor;
-
-        assert(link);
-        assert(neighbor);
-
-        if (!link->network)
-                return false;
-
-        LIST_FOREACH(neighbors, net_neighbor, link->network->neighbors)
-                if (neighbor_equal(net_neighbor, neighbor))
-                        return true;
-
-        return false;
-}
-
-static bool link_is_static_route_configured(Link *link, Route *route) {
-        Route *net_route;
-
-        assert(link);
-        assert(route);
-
-        if (!link->network)
-                return false;
-
-        LIST_FOREACH(routes, net_route, link->network->static_routes)
-                if (route_equal(net_route, route))
-                        return true;
-
-        return false;
-}
-
-static bool link_address_is_dynamic(Link *link, Address *address) {
-        Route *route;
-
-        assert(link);
-        assert(address);
-
-        if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
-                return true;
-
-        /* Even when the address is leased from a DHCP server, networkd assign the address
-         * without lifetime when KeepConfiguration=dhcp. So, let's check that we have
-         * corresponding routes with RTPROT_DHCP. */
-        SET_FOREACH(route, link->routes_foreign) {
-                if (route->protocol != RTPROT_DHCP)
-                        continue;
-
-                if (address->family != route->family)
-                        continue;
-
-                if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
-                        return true;
-        }
-
-        return false;
-}
-
-static int link_enumerate_ipv6_tentative_addresses(Link *link) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *addr;
-        int r;
-
-        assert(link);
-        assert(link->manager);
-        assert(link->manager->rtnl);
+                return r;
 
-        r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, 0, AF_INET6);
+        r = link_drop_neighbors(link);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_call(link->manager->rtnl, req, 0, &reply);
+        r = link_drop_routes(link);
         if (r < 0)
                 return r;
 
-        for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
-                unsigned char flags;
-                int ifindex;
-
-                r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: invalid ifindex, ignoring: %m");
-                        continue;
-                } else if (link->ifindex != ifindex)
-                        continue;
-
-                r = sd_rtnl_message_addr_get_flags(addr, &flags);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
-                        continue;
-                } else if (!(flags & IFA_F_TENTATIVE))
-                        continue;
-
-                log_link_debug(link, "Found tentative ipv6 link-local address");
-                (void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager);
-        }
-
-        return 0;
-}
-
-static int link_drop_foreign_config(Link *link) {
-        Address *address;
-        Neighbor *neighbor;
-        Route *route;
-        int r;
-
-        /* The kernel doesn't notify us about tentative addresses;
-         * so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */
-        if (!link_ipv6ll_enabled(link)) {
-                r = link_enumerate_ipv6_tentative_addresses(link);
-                if (r < 0)
-                        return r;
-        }
-
-        SET_FOREACH(address, link->addresses_foreign) {
-                /* we consider IPv6LL addresses to be managed by the kernel */
-                if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
-                        continue;
-
-                if (link_address_is_dynamic(link, address)) {
-                        if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
-                                continue;
-                } else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
-                        continue;
-
-                if (link_is_static_address_configured(link, address)) {
-                        r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
-                        if (r < 0)
-                                return log_link_error_errno(link, r, "Failed to add address: %m");
-                } else {
-                        r = address_remove(address, link, NULL);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        SET_FOREACH(neighbor, link->neighbors_foreign) {
-                if (link_is_neighbor_configured(link, neighbor)) {
-                        r = neighbor_add(link, neighbor->family, &neighbor->in_addr, &neighbor->lladdr, neighbor->lladdr_size, NULL);
-                        if (r < 0)
-                                return r;
-                } else {
-                        r = neighbor_remove(neighbor, link, NULL);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        SET_FOREACH(route, link->routes_foreign) {
-                /* do not touch routes managed by the kernel */
-                if (route->protocol == RTPROT_KERNEL)
-                        continue;
-
-                /* do not touch multicast route added by kernel */
-                /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
-                 * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
-                if (route->protocol == RTPROT_BOOT &&
-                    route->family == AF_INET6 &&
-                    route->dst_prefixlen == 8 &&
-                    in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
-                        continue;
-
-                if (route->protocol == RTPROT_STATIC && link->network &&
-                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
-                        continue;
-
-                if (route->protocol == RTPROT_DHCP && link->network &&
-                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
-                        continue;
-
-                if (link_is_static_route_configured(link, route)) {
-                        r = route_add(link, route, NULL);
-                        if (r < 0)
-                                return r;
-                } else {
-                        r = route_remove(route, link, NULL);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        return 0;
-}
-
-static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        int r;
-
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-        assert(link->address_remove_messages > 0);
-
-        link->address_remove_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 != -EADDRNOTAVAIL)
-                log_link_message_warning_errno(link, m, r, "Could not drop address");
-        else if (r >= 0)
-                (void) manager_rtnl_process_address(rtnl, m, link->manager);
-
-        if (link->address_remove_messages == 0 && link->request_static_addresses) {
-                link_set_state(link, LINK_STATE_CONFIGURING);
-                r = link_request_set_addresses(link);
-                if (r < 0)
-                        link_enter_failed(link);
-        }
-
-        return 1;
-}
-
-static int link_drop_config(Link *link) {
-        Address *address, *pool_address;
-        Neighbor *neighbor;
-        Route *route;
-        int r;
-
-        SET_FOREACH(address, link->addresses) {
-                /* we consider IPv6LL addresses to be managed by the kernel */
-                if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
-                        continue;
-
-                r = address_remove(address, link, remove_static_address_handler);
-                if (r < 0)
-                        return r;
-
-                link->address_remove_messages++;
-
-                /* If this address came from an address pool, clean up the pool */
-                LIST_FOREACH(addresses, pool_address, link->pool_addresses)
-                        if (address_equal(address, pool_address)) {
-                                LIST_REMOVE(addresses, link->pool_addresses, pool_address);
-                                address_free(pool_address);
-                                break;
-                        }
-        }
-
-        SET_FOREACH(neighbor, link->neighbors) {
-                r = neighbor_remove(neighbor, link, NULL);
-                if (r < 0)
-                        return r;
-        }
-
-        SET_FOREACH(route, link->routes) {
-                /* do not touch routes managed by the kernel */
-                if (route->protocol == RTPROT_KERNEL)
-                        continue;
-
-                r = route_remove(route, link, NULL);
-                if (r < 0)
-                        return r;
-        }
-
-        ndisc_flush(link);
-
-        return 0;
-}
-
-static int link_configure_ipv4_dad(Link *link) {
-        Address *address;
-        int r;
-
-        assert(link);
-        assert(link->network);
-
-        LIST_FOREACH(addresses, address, link->network->static_addresses)
-                if (address->family == AF_INET &&
-                    FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
-                        r = configure_ipv4_duplicate_address_detection(link, address);
-                        if (r < 0)
-                                return log_link_error_errno(link, r, "Failed to configure IPv4ACD: %m");
-                }
-
-        return 0;
-}
-
-static int link_configure_traffic_control(Link *link) {
-        TrafficControl *tc;
-        int r;
-
-        link->tc_configured = false;
-        link->tc_messages = 0;
-
-        ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) {
-                r = traffic_control_configure(link, tc);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link->tc_messages == 0)
-                link->tc_configured = true;
-        else
-                log_link_debug(link, "Configuring traffic control");
-
-        return 0;
-}
-
-static int link_configure_sr_iov(Link *link) {
-        SRIOV *sr_iov;
-        int r;
-
-        link->sr_iov_configured = false;
-        link->sr_iov_messages = 0;
-
-        ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
-                r = sr_iov_configure(link, sr_iov);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link->sr_iov_messages == 0)
-                link->sr_iov_configured = true;
-        else
-                log_link_debug(link, "Configuring SR-IOV");
+        ndisc_flush(link);
 
         return 0;
 }
 
-static int link_configure(Link *link) {
+int link_configure(Link *link) {
         int r;
 
         assert(link);
@@ -3046,114 +2048,59 @@ static int link_configure(Link *link) {
         if (link->iftype == ARPHRD_CAN)
                 return link_configure_can(link);
 
-        /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
-         * for this interface, then enable IPv6 */
-        (void) link_update_ipv6_sysctl(link);
-
-        r = link_set_proxy_arp(link);
+        r = link_set_sysctl(link);
         if (r < 0)
-               return r;
+                return r;
 
-        r = ipv6_proxy_ndp_addresses_configure(link);
+        r = link_set_ipv6_proxy_ndp_addresses(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv4_forward(link);
+        r = link_set_mac(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv6_forward(link);
+        r = link_set_nomaster(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv6_privacy_extensions(link);
+        r = link_set_flags(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv6_accept_ra(link);
+        r = link_set_group(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv6_dad_transmits(link);
+        r = ipv4ll_configure(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv6_hop_limit(link);
+        r = dhcp4_configure(link);
         if (r < 0)
                 return r;
 
-        r = link_set_ipv4_accept_local(link);
+        r = dhcp6_configure(link);
         if (r < 0)
                 return r;
 
-        r = link_set_flags(link);
+        r = ndisc_configure(link);
         if (r < 0)
                 return r;
 
-        r = link_set_group(link);
+        r = radv_configure(link);
         if (r < 0)
                 return r;
 
-        if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
-                r = ipv4ll_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_dhcp4_enabled(link)) {
-                r = dhcp4_set_promote_secondaries(link);
-                if (r < 0)
-                        return r;
-
-                r = dhcp4_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_dhcp4_server_enabled(link)) {
-                r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
-                if (r < 0)
-                        return r;
-
-                r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_dhcp6_enabled(link) ||
-            link_ipv6_accept_ra_enabled(link)) {
-                r = dhcp6_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_ipv6_accept_ra_enabled(link)) {
-                r = ndisc_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_radv_enabled(link)) {
-                r = radv_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link_lldp_rx_enabled(link)) {
-                r = link_lldp_rx_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        r = link_configure_mtu(link);
+        r = link_lldp_rx_configure(link);
         if (r < 0)
                 return r;
 
-        r = link_configure_addrgen_mode(link);
+        r = link_configure_mtu(link);
         if (r < 0)
                 return r;
 
-        r = link_configure_ipv4_dad(link);
+        r = link_configure_addrgen_mode(link);
         if (r < 0)
                 return r;
 
@@ -3195,150 +2142,11 @@ static int link_configure_continue(Link *link) {
          * we must set this here, after we've set device mtu */
         r = link_set_ipv6_mtu(link);
         if (r < 0)
-                return r;
-
-        if (link_has_carrier(link) || link->network->configure_without_carrier) {
-                r = link_acquire_conf(link);
-                if (r < 0)
-                        return r;
-        }
+                log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface, ignoring: %m");
 
         return link_enter_join_netdev(link);
 }
 
-static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
-        assert(duid);
-
-        if (duid->raw_data_len > 0)
-                return 0;
-
-        if (duid->type != DUID_TYPE_UUID)
-                return -EINVAL;
-
-        memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
-        duid->raw_data_len = sizeof(sd_id128_t);
-
-        return 1;
-}
-
-int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        Manager *manager = userdata;
-        const sd_bus_error *e;
-        const void *a;
-        size_t sz;
-        DUID *duid;
-        Link *link;
-        int r;
-
-        assert(m);
-        assert(manager);
-
-        e = sd_bus_message_get_error(m);
-        if (e) {
-                log_error_errno(sd_bus_error_get_errno(e),
-                                "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
-                                e->message);
-                goto configure;
-        }
-
-        r = sd_bus_message_read_array(m, 'y', &a, &sz);
-        if (r < 0)
-                goto configure;
-
-        if (sz != sizeof(sd_id128_t)) {
-                log_error("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
-                goto configure;
-        }
-
-        memcpy(&manager->product_uuid, a, sz);
-        while ((duid = set_steal_first(manager->duids_requesting_uuid)))
-                (void) duid_set_uuid(duid, manager->product_uuid);
-
-        manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
-
-configure:
-        while ((link = set_steal_first(manager->links_requesting_uuid))) {
-                link_unref(link);
-
-                r = link_configure(link);
-                if (r < 0)
-                        link_enter_failed(link);
-        }
-
-        manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
-
-        /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
-         * even if the method fails. */
-        manager->has_product_uuid = true;
-
-        return 1;
-}
-
-static bool link_requires_uuid(Link *link) {
-        const DUID *duid;
-
-        assert(link);
-        assert(link->manager);
-        assert(link->network);
-
-        duid = link_get_duid(link);
-        if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
-                return false;
-
-        if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
-                return true;
-
-        if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
-                return true;
-
-        return false;
-}
-
-static int link_configure_duid(Link *link) {
-        Manager *m;
-        DUID *duid;
-        int r;
-
-        assert(link);
-        assert(link->manager);
-        assert(link->network);
-
-        m = link->manager;
-        duid = link_get_duid(link);
-
-        if (!link_requires_uuid(link))
-                return 1;
-
-        if (m->has_product_uuid) {
-                (void) duid_set_uuid(duid, m->product_uuid);
-                return 1;
-        }
-
-        if (!m->links_requesting_uuid) {
-                r = manager_request_product_uuid(m, link);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                return r;
-
-                        log_link_warning_errno(link, r,
-                                               "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
-                        return 1;
-                }
-        } else {
-                r = set_put(m->links_requesting_uuid, link);
-                if (r < 0)
-                        return log_oom();
-                if (r > 0)
-                        link_ref(link);
-
-                r = set_put(m->duids_requesting_uuid, duid);
-                if (r < 0)
-                        return log_oom();
-        }
-
-        return 0;
-}
-
 static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool force) {
         Network *network;
         int r;
@@ -3376,13 +2184,10 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
         log_link_info(link, "Re-configuring with %s", network->filename);
 
         /* Dropping old .network file */
-        r = link_stop_clients(link, false);
+        r = link_stop_engines(link, false);
         if (r < 0)
                 return r;
 
-        if (link_dhcp4_server_enabled(link))
-                (void) sd_dhcp_server_stop(link->dhcp_server);
-
         r = link_drop_config(link);
         if (r < 0)
                 return r;
@@ -3612,7 +2417,6 @@ static int link_load(Link *link) {
                             *routes = NULL,
                             *dhcp4_address = NULL,
                             *ipv4ll_address = NULL;
-        union in_addr_union address;
         int r;
 
         assert(link);
@@ -3651,145 +2455,21 @@ static int link_load(Link *link) {
 
 network_file_fail:
 
-        for (const char *p = addresses; p; ) {
-                _cleanup_free_ char *address_str = NULL;
-                char *prefixlen_str;
-                int family;
-                unsigned char prefixlen;
-
-                r = extract_first_word(&p, &address_str, NULL, 0);
-                if (r < 0)
-                        log_link_warning_errno(link, r, "failed to parse ADDRESSES: %m");
-                if (r <= 0)
-                        break;
-
-                prefixlen_str = strchr(address_str, '/');
-                if (!prefixlen_str) {
-                        log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
-                        continue;
-                }
-                *prefixlen_str++ = '\0';
-
-                r = sscanf(prefixlen_str, "%hhu", &prefixlen);
-                if (r != 1) {
-                        log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
-                        continue;
-                }
-
-                r = in_addr_from_string_auto(address_str, &family, &address);
-                if (r < 0) {
-                        log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
-                        continue;
-                }
-
-                r = address_add(link, family, &address, prefixlen, NULL);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to add address: %m");
-        }
-
-        for (const char *p = routes; p; ) {
-                _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
-                _cleanup_(route_freep) Route *tmp = NULL;
-                _cleanup_free_ char *route_str = NULL;
-                char *prefixlen_str;
-                Route *route;
-
-                r = extract_first_word(&p, &route_str, NULL, 0);
-                if (r < 0)
-                        log_link_debug_errno(link, r, "failed to parse ROUTES: %m");
-                if (r <= 0)
-                        break;
-
-                prefixlen_str = strchr(route_str, '/');
-                if (!prefixlen_str) {
-                        log_link_debug(link, "Failed to parse route %s", route_str);
-                        continue;
-                }
-                *prefixlen_str++ = '\0';
-
-                r = route_new(&tmp);
-                if (r < 0)
-                        return log_oom();
-
-                r = sscanf(prefixlen_str,
-                           "%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
-                           &tmp->dst_prefixlen,
-                           &tmp->tos,
-                           &tmp->priority,
-                           &tmp->table,
-                           &tmp->lifetime);
-                if (r != 5) {
-                        log_link_debug(link,
-                                       "Failed to parse destination prefix length, tos, priority, table or expiration %s",
-                                       prefixlen_str);
-                        continue;
-                }
-
-                r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
-                if (r < 0) {
-                        log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
-                        continue;
-                }
-
-                r = route_add(link, tmp, &route);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to add route: %m");
-
-                if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
-                        r = sd_event_add_time(link->manager->event, &expire,
-                                              clock_boottime_or_monotonic(),
-                                              route->lifetime, 0, route_expire_handler, route);
-                        if (r < 0)
-                                log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
-                }
-
-                sd_event_source_unref(route->expire);
-                route->expire = TAKE_PTR(expire);
-        }
-
-        if (dhcp4_address) {
-                r = in_addr_from_string(AF_INET, dhcp4_address, &address);
-                if (r < 0) {
-                        log_link_debug_errno(link, r, "Failed to parse DHCPv4 address %s: %m", dhcp4_address);
-                        goto dhcp4_address_fail;
-                }
-
-                r = sd_dhcp_client_new(&link->dhcp_client, link->network ? link->network->dhcp_anonymize : 0);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
-
-                r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to attach DHCPv4 event: %m");
-
-                r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to set initial DHCPv4 address %s: %m", dhcp4_address);
-        }
-
-dhcp4_address_fail:
-
-        if (ipv4ll_address) {
-                r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
-                if (r < 0) {
-                        log_link_debug_errno(link, r, "Failed to parse IPv4LL address %s: %m", ipv4ll_address);
-                        goto ipv4ll_address_fail;
-                }
-
-                r = sd_ipv4ll_new(&link->ipv4ll);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to create IPv4LL client: %m");
+        r = link_deserialize_addresses(link, addresses);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to load addresses from %s, ignoring: %m", link->state_file);
 
-                r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to attach IPv4LL event: %m");
+        r = link_deserialize_routes(link, routes);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to load routes from %s, ignoring: %m", link->state_file);
 
-                r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address);
-        }
+        r = link_deserialize_dhcp4(link, dhcp4_address);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to load DHCPv4 address from %s, ignoring: %m", link->state_file);
 
-ipv4ll_address_fail:
+        r = link_deserialize_ipv4ll(link, ipv4ll_address);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to load IPv4LL address from %s, ignoring: %m", link->state_file);
 
         return 0;
 }
@@ -3907,7 +2587,7 @@ static int link_carrier_gained(Link *link) {
                 }
 
                 link_set_state(link, LINK_STATE_CONFIGURING);
-                r = link_request_set_addresses(link);
+                r = link_set_static_configs(link);
                 if (r < 0)
                         return r;
         }
@@ -3952,15 +2632,12 @@ static int link_carrier_lost(Link *link) {
         if (link->setting_mtu)
                 return 0;
 
-        r = link_stop_clients(link, false);
+        r = link_stop_engines(link, false);
         if (r < 0) {
                 link_enter_failed(link);
                 return r;
         }
 
-        if (link_dhcp4_server_enabled(link))
-                (void) sd_dhcp_server_stop(link->dhcp_server);
-
         r = link_drop_config(link);
         if (r < 0)
                 return r;
@@ -4093,101 +2770,31 @@ int link_update(Link *link, sd_netlink_message *m) {
                                mac.ether_addr_octet[4],
                                mac.ether_addr_octet[5]);
 
-                if (link->ipv4ll) {
-                        bool restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
-
-                        if (restart) {
-                                r = sd_ipv4ll_stop(link->ipv4ll);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not stop IPv4LL client: %m");
-                        }
-
-                        r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
-
-                        if (restart) {
-                                r = sd_ipv4ll_start(link->ipv4ll);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not restart IPv4LL client: %m");
-                        }
-                }
-
-                if (link->dhcp_client) {
-                        r = sd_dhcp_client_set_mac(link->dhcp_client,
-                                                   (const uint8_t *) &link->mac,
-                                                   sizeof (link->mac),
-                                                   ARPHRD_ETHER);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
-
-                        r = dhcp4_set_client_identifier(link);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not set DHCP client identifier: %m");
-                }
-
-                if (link->dhcp6_client) {
-                        const DUID* duid = link_get_duid(link);
-                        bool restart = sd_dhcp6_client_is_running(link->dhcp6_client) > 0;
-
-                        if (restart) {
-                                r = sd_dhcp6_client_stop(link->dhcp6_client);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
-                        }
-
-                        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
-                                                    (const uint8_t *) &link->mac,
-                                                    sizeof (link->mac),
-                                                    ARPHRD_ETHER);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
-
-                        if (link->network->iaid_set) {
-                                r = sd_dhcp6_client_set_iaid(link->dhcp6_client, link->network->iaid);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
-                        }
-
-                        r = sd_dhcp6_client_set_duid(link->dhcp6_client,
-                                                     duid->type,
-                                                     duid->raw_data_len > 0 ? duid->raw_data : NULL,
-                                                     duid->raw_data_len);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
-
-                        if (restart) {
-                                r = sd_dhcp6_client_start(link->dhcp6_client);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not restart DHCPv6 client: %m");
-                        }
-                }
-
-                if (link->radv) {
-                        bool restart = sd_radv_is_running(link->radv);
+                r = ipv4ll_update_mac(link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
 
-                        if (restart) {
-                                r = sd_radv_stop(link->radv);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not stop Router Advertisement: %m");
-                        }
+                r = dhcp4_update_mac(link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
 
-                        r = sd_radv_set_mac(link->radv, &link->mac);
-                        if (r < 0)
-                                return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
+                r = dhcp6_update_mac(link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
 
-                        if (restart) {
-                                r = sd_radv_start(link->radv);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not restart Router Advertisement: %m");
-                        }
-                }
+                r = dhcp6_update_mac(link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not update MAC address for Router Advertisement: %m");
 
                 if (link->ndisc) {
                         r = sd_ndisc_set_mac(link->ndisc, &link->mac);
                         if (r < 0)
                                 return log_link_warning_errno(link, r, "Could not update MAC for NDisc: %m");
                 }
+
+                r = ipv4_dad_update_mac(link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m");
         }
 
         old_master = link->master_ifindex;
@@ -4327,8 +2934,6 @@ int link_save(Link *link) {
         const char *admin_state, *oper_state, *carrier_state, *address_state;
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        Route *route;
-        Address *a;
         int r;
 
         assert(link);
@@ -4546,38 +3151,15 @@ int link_save(Link *link) {
 
                 /************************************************************/
 
-                fputs("ADDRESSES=", f);
-                space = false;
-                SET_FOREACH(a, link->addresses) {
-                        _cleanup_free_ char *address_str = NULL;
-
-                        r = in_addr_to_string(a->family, &a->in_addr, &address_str);
-                        if (r < 0)
-                                goto fail;
-
-                        fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
-                        space = true;
-                }
-                fputc('\n', f);
+                r = link_serialize_addresses(link, f);
+                if (r < 0)
+                        goto fail;
 
                 /************************************************************/
 
-                fputs("ROUTES=", f);
-                space = false;
-                SET_FOREACH(route, link->routes) {
-                        _cleanup_free_ char *route_str = NULL;
-
-                        r = in_addr_to_string(route->family, &route->dst, &route_str);
-                        if (r < 0)
-                                goto fail;
-
-                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
-                                space ? " " : "", route_str,
-                                route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
-                        space = true;
-                }
-
-                fputc('\n', f);
+                r = link_serialize_routes(link, f);
+                if (r < 0)
+                        goto fail;
         }
 
         print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
@@ -4594,29 +3176,13 @@ int link_save(Link *link) {
         } else
                 (void) unlink(link->lease_file);
 
-        if (link->ipv4ll) {
-                struct in_addr address;
-
-                r = sd_ipv4ll_get_address(link->ipv4ll, &address);
-                if (r >= 0) {
-                        fputs("IPV4LL_ADDRESS=", f);
-                        serialize_in_addrs(f, &address, 1, false, NULL);
-                        fputc('\n', f);
-                }
-        }
-
-        if (link->dhcp6_client) {
-                _cleanup_free_ char *duid = NULL;
-                uint32_t iaid;
-
-                r = sd_dhcp6_client_get_iaid(link->dhcp6_client, &iaid);
-                if (r >= 0)
-                        fprintf(f, "DHCP6_CLIENT_IAID=0x%x\n", iaid);
+        r = link_serialize_ipv4ll(link, f);
+        if (r < 0)
+                goto fail;
 
-                r = sd_dhcp6_client_duid_as_string(link->dhcp6_client, &duid);
-                if (r >= 0)
-                        fprintf(f, "DHCP6_CLIENT_DUID=%s\n", duid);
-        }
+        r = link_serialize_dhcp6_client(link, f);
+        if (r < 0)
+                goto fail;
 
         r = fflush_and_check(f);
         if (r < 0)
index 1550db8a23926edfd0f485300d063099812cd4de..a7ae2645f95817461eaf74e71e581369c48bb779 100644 (file)
@@ -9,13 +9,13 @@
 #include "sd-dhcp-client.h"
 #include "sd-dhcp-server.h"
 #include "sd-dhcp6-client.h"
+#include "sd-ipv4acd.h"
 #include "sd-ipv4ll.h"
 #include "sd-lldp.h"
 #include "sd-ndisc.h"
 #include "sd-radv.h"
 #include "sd-netlink.h"
 
-#include "list.h"
 #include "log-link.h"
 #include "network-util.h"
 #include "networkd-util.h"
@@ -89,6 +89,7 @@ typedef struct Link {
 
         Set *addresses;
         Set *addresses_foreign;
+        Set *pool_addresses;
         Set *static_addresses;
         Set *neighbors;
         Set *neighbors_foreign;
@@ -105,6 +106,7 @@ typedef struct Link {
         uint32_t original_mtu;
         unsigned dhcp4_messages;
         unsigned dhcp4_remove_messages;
+        sd_ipv4acd *dhcp_acd;
         bool dhcp4_route_failed:1;
         bool dhcp4_route_retrying:1;
         bool dhcp4_configured:1;
@@ -127,8 +129,6 @@ typedef struct Link {
         bool ipv6_mtu_set:1;
         bool bridge_mdb_configured:1;
 
-        LIST_HEAD(Address, pool_addresses);
-
         sd_dhcp_server *dhcp_server;
 
         sd_ndisc *ndisc;
@@ -193,9 +193,6 @@ typedef struct 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);
-
 void link_ntp_settings_clear(Link *link);
 void link_dns_settings_clear(Link *link);
 Link *link_unref(Link *link);
@@ -226,22 +223,20 @@ int link_save_and_clean(Link *link);
 int link_carrier_reset(Link *link);
 bool link_has_carrier(Link *link);
 
+bool link_ipv6_enabled(Link *link);
+bool link_ipv6ll_enabled(Link *link);
 int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
 
 int link_set_mtu(Link *link, uint32_t mtu);
 
 bool link_ipv4ll_enabled(Link *link, AddressFamily mask);
 
-int link_stop_clients(Link *link, bool may_keep_dhcp);
+int link_stop_engines(Link *link, bool may_keep_dhcp);
 
 const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
 
-uint32_t link_get_vrf_table(Link *link);
-uint32_t link_get_dhcp_route_table(Link *link);
-uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
-int link_request_set_routes(Link *link);
-
+int link_configure(Link *link);
 int link_reconfigure(Link *link, bool force);
 
 int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);
@@ -250,9 +245,3 @@ int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, in
 #define log_link_message_notice_errno(link, m, err, msg)  log_link_message_full_errno(link, m, LOG_NOTICE, err, msg)
 #define log_link_message_info_errno(link, m, err, msg)    log_link_message_full_errno(link, m, LOG_INFO, err, msg)
 #define log_link_message_debug_errno(link, m, err, msg)   log_link_message_full_errno(link, m, LOG_DEBUG, err, msg)
-
-#define ADDRESS_FMT_VAL(address)                   \
-        be32toh((address).s_addr) >> 24,           \
-        (be32toh((address).s_addr) >> 16) & 0xFFu, \
-        (be32toh((address).s_addr) >> 8) & 0xFFu,  \
-        be32toh((address).s_addr) & 0xFFu
index fe8877797719516e7cef4ee895f6ae94b7adb15f..65a8a314d602adf6412fdf74bc7b5d9492a8f52e 100644 (file)
@@ -9,6 +9,7 @@
 #include "networkd-link.h"
 #include "networkd-lldp-rx.h"
 #include "networkd-lldp-tx.h"
+#include "networkd-manager.h"
 #include "networkd-network.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -25,7 +26,7 @@ static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
 
-bool link_lldp_rx_enabled(Link *link) {
+static bool link_lldp_rx_enabled(Link *link) {
         assert(link);
 
         if (link->flags & IFF_LOOPBACK)
@@ -68,9 +69,18 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n
 int link_lldp_rx_configure(Link *link) {
         int r;
 
-        r = sd_lldp_new(&link->lldp);
-        if (r < 0)
-                return r;
+        if (!link_lldp_rx_enabled(link))
+                return 0;
+
+        if (!link->lldp) {
+                r = sd_lldp_new(&link->lldp);
+                if (r < 0)
+                        return r;
+
+                r = sd_lldp_attach_event(link->lldp, link->manager->event, 0);
+                if (r < 0)
+                        return r;
+        }
 
         r = sd_lldp_set_ifindex(link->lldp, link->ifindex);
         if (r < 0)
@@ -87,10 +97,6 @@ int link_lldp_rx_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = sd_lldp_attach_event(link->lldp, NULL, 0);
-        if (r < 0)
-                return r;
-
         r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
         if (r < 0)
                 return r;
index 12f512f62870287d9ff767687102b87a78db3f53..8e1a6a0b62101bff6f4632e8a999f4bdaf6bc685 100644 (file)
@@ -1,8 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <stdbool.h>
-
 #include "conf-parser.h"
 
 typedef struct Link Link;
@@ -15,7 +13,6 @@ typedef enum LLDPMode {
         _LLDP_MODE_INVALID = -1,
 } LLDPMode;
 
-bool link_lldp_rx_enabled(Link *link);
 int link_lldp_rx_configure(Link *link);
 int link_update_lldp(Link *link);
 int link_lldp_save(Link *link);
index 2be7c27e1821182173ed3c8ef3fe2bbe9fa014fc..c8e56a5fece64efcf06a73531711a8f6978c67c3 100644 (file)
@@ -367,7 +367,7 @@ int link_lldp_emit_start(Link *link) {
 
         assert(link);
 
-        if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
+        if (!link_lldp_emit_enabled(link)) {
                 link_lldp_emit_stop(link);
                 return 0;
         }
index dbbc6b64bcc753d2f14dc81270e82b9b99d4c960..b5aba1f1dc2f33c4d96fc5994d65e86daffbea31 100644 (file)
 #include "local-addresses.h"
 #include "netlink-util.h"
 #include "network-internal.h"
+#include "networkd-address-pool.h"
 #include "networkd-dhcp-server-bus.h"
 #include "networkd-dhcp6.h"
 #include "networkd-link-bus.h"
 #include "networkd-manager-bus.h"
 #include "networkd-manager.h"
+#include "networkd-neighbor.h"
 #include "networkd-network-bus.h"
+#include "networkd-nexthop.h"
+#include "networkd-routing-policy-rule.h"
 #include "networkd-speed-meter.h"
 #include "ordered-set.h"
 #include "path-lookup.h"
 /* use 128 MB for receive socket kernel queue. */
 #define RCVBUF_SIZE    (128*1024*1024)
 
-static int log_message_warning_errno(sd_netlink_message *m, int err, const char *msg) {
-        const char *err_msg = NULL;
-
-        (void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
-        return log_warning_errno(err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
-}
-
-static int setup_default_address_pool(Manager *m) {
-        AddressPool *p;
-        int r;
-
-        assert(m);
-
-        /* Add in the well-known private address ranges. */
-
-        r = address_pool_new_from_string(m, &p, AF_INET6, "fd00::", 8);
-        if (r < 0)
-                return r;
-
-        r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
-        if (r < 0)
-                return r;
-
-        r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
-        if (r < 0)
-                return r;
-
-        r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
 static int manager_reset_all(Manager *m) {
         Link *link;
         int r;
@@ -261,961 +231,40 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi
 static int manager_connect_udev(Manager *m) {
         int r;
 
-        /* udev does not initialize devices inside containers, so we rely on them being already
-         * initialized before entering the container. */
-        if (path_is_read_only_fs("/sys") > 0)
-                return 0;
-
-        r = sd_device_monitor_new(&m->device_monitor);
-        if (r < 0)
-                return log_error_errno(r, "Failed to initialize device monitor: %m");
-
-        r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
-        if (r < 0)
-                log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
-
-        r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
-        if (r < 0)
-                return log_error_errno(r, "Could not add device monitor filter: %m");
-
-        r = sd_device_monitor_attach_event(m->device_monitor, m->event);
-        if (r < 0)
-                return log_error_errno(r, "Failed to attach event to device monitor: %m");
-
-        r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to start device monitor: %m");
-
-        return 0;
-}
-
-int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        _cleanup_(route_freep) Route *tmp = NULL;
-        Route *route = NULL;
-        Manager *m = userdata;
-        Link *link = NULL;
-        uint32_t ifindex;
-        uint16_t type;
-        unsigned char table;
-        int r;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
-                if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
-
-                return 0;
-        }
-
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
-                log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
-        if (r == -ENODATA) {
-                log_debug("rtnl: received route message without ifindex, ignoring");
-                return 0;
-        } else if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
-                return 0;
-        } else if (ifindex <= 0) {
-                log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = link_get(m, ifindex, &link);
-        if (r < 0 || !link) {
-                /* when enumerating we might be out of sync, but we will
-                 * get the route again, so just ignore it */
-                if (!m->enumerating)
-                        log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
-                return 0;
-        }
-
-        r = route_new(&tmp);
-        if (r < 0)
-                return log_oom();
-
-        r = sd_rtnl_message_route_get_family(message, &tmp->family);
-        if (r < 0) {
-                log_link_warning(link, "rtnl: received route message without family, ignoring");
-                return 0;
-        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
-                log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: received route message without route protocol: %m");
-                return 0;
-        }
-
-        switch (tmp->family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Received route message with unsupported address family");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_type(message, &tmp->type);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_route_get_table(message, &table);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
-                return 0;
-        }
-        tmp->table = table;
-
-        r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
-        if (r < 0 && r != -ENODATA) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_enter_container(message, RTA_METRICS);
-        if (r < 0 && r != -ENODATA) {
-                log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
-                return 0;
-        }
-        if (r >= 0) {
-                r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
-                        return 0;
-                }
-
-                r = sd_netlink_message_exit_container(message);
-                if (r < 0) {
-                        log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
-                        return 0;
-                }
-        }
-
-        (void) route_get(link, tmp, &route);
-
-        if (DEBUG_LOGGING) {
-                _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
-                        *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
-                char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
-                        buf_protocol[ROUTE_PROTOCOL_STR_MAX];
-
-                if (!in_addr_is_null(tmp->family, &tmp->dst)) {
-                        (void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
-                        (void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
-                }
-                if (!in_addr_is_null(tmp->family, &tmp->src))
-                        (void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
-                if (!in_addr_is_null(tmp->family, &tmp->gw))
-                        (void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
-                if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
-                        (void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
-
-                log_link_debug(link,
-                               "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
-                               (!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
-                               type == RTM_DELROUTE ? "Forgetting" :
-                               route ? "Received remembered" : "Remembering",
-                               strna(buf_dst), strempty(buf_dst_prefixlen),
-                               strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
-                               format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
-                               format_route_table(tmp->table, buf_table, sizeof buf_table),
-                               format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
-                               strna(route_type_to_string(tmp->type)));
-        }
-
-        switch (type) {
-        case RTM_NEWROUTE:
-                if (!route && link->manager->manage_foreign_routes) {
-                        /* A route appeared that we did not request */
-                        r = route_add_foreign(link, tmp, &route);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                break;
-
-        case RTM_DELROUTE:
-                route_free(route);
-                break;
-
-        default:
-                assert_not_reached("Received route message with invalid RTNL message type");
-        }
-
-        return 1;
-}
-
-static int manager_rtnl_process_neighbor_lladdr(sd_netlink_message *message, union lladdr_union *lladdr, size_t *size, char **str) {
-        int r;
-
-        assert(message);
-        assert(lladdr);
-        assert(size);
-        assert(str);
-
-        *str = NULL;
-
-        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in6), &lladdr->ip.in6);
-        if (r >= 0) {
-                *size = sizeof(lladdr->ip.in6);
-                if (in_addr_to_string(AF_INET6, &lladdr->ip, str) < 0)
-                        log_warning_errno(r, "Could not print lower address: %m");
-                return r;
-        }
-
-        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->mac), &lladdr->mac);
-        if (r >= 0) {
-                *size = sizeof(lladdr->mac);
-                *str = new(char, ETHER_ADDR_TO_STRING_MAX);
-                if (!*str) {
-                        log_oom();
-                        return r;
-                }
-                ether_addr_to_string(&lladdr->mac, *str);
-                return r;
-        }
-
-        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in), &lladdr->ip.in);
-        if (r >= 0) {
-                *size = sizeof(lladdr->ip.in);
-                if (in_addr_to_string(AF_INET, &lladdr->ip, str) < 0)
-                        log_warning_errno(r, "Could not print lower address: %m");
-                return r;
-        }
-
-        return r;
-}
-
-int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        Manager *m = userdata;
-        Link *link = NULL;
-        Neighbor *neighbor = NULL;
-        int ifindex, family, r;
-        uint16_t type, state;
-        union in_addr_union in_addr = IN_ADDR_NULL;
-        _cleanup_free_ char *addr_str = NULL;
-        union lladdr_union lladdr;
-        size_t lladdr_size = 0;
-        _cleanup_free_ char *lladdr_str = NULL;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
-                if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
-
-                return 0;
-        }
-
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(type, RTM_NEWNEIGH, RTM_DELNEIGH)) {
-                log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type);
-                return 0;
-        }
-
-        r = sd_rtnl_message_neigh_get_state(message, &state);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid state, ignoring: %m");
-                return 0;
-        } else if (!FLAGS_SET(state, NUD_PERMANENT)) {
-                log_debug("rtnl: received non-static neighbor, ignoring.");
-                return 0;
-        }
-
-        r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
-                return 0;
-        } else if (ifindex <= 0) {
-                log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = link_get(m, ifindex, &link);
-        if (r < 0 || !link) {
-                /* when enumerating we might be out of sync, but we will get the neighbor again, so just
-                 * ignore it */
-                if (!m->enumerating)
-                        log_warning("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = sd_rtnl_message_neigh_get_family(message, &family);
-        if (r < 0) {
-                log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
-                return 0;
-        } else if (!IN_SET(family, AF_INET, AF_INET6)) {
-                log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", family);
-                return 0;
-        }
-
-        switch (family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, NDA_DST, &in_addr.in);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, NDA_DST, &in_addr.in6);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Received unsupported address family");
-        }
-
-        if (in_addr_to_string(family, &in_addr, &addr_str) < 0)
-                log_link_warning_errno(link, r, "Could not print address: %m");
-
-        r = manager_rtnl_process_neighbor_lladdr(message, &lladdr, &lladdr_size, &lladdr_str);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid lladdr, ignoring: %m");
-                return 0;
-        }
-
-        (void) neighbor_get(link, family, &in_addr, &lladdr, lladdr_size, &neighbor);
-
-        switch (type) {
-        case RTM_NEWNEIGH:
-                if (neighbor)
-                        log_link_debug(link, "Received remembered neighbor: %s->%s",
-                                       strnull(addr_str), strnull(lladdr_str));
-                else {
-                        /* A neighbor appeared that we did not request */
-                        r = neighbor_add_foreign(link, family, &in_addr, &lladdr, lladdr_size, &neighbor);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Failed to remember foreign neighbor %s->%s, ignoring: %m",
-                                                       strnull(addr_str), strnull(lladdr_str));
-                                return 0;
-                        } else
-                                log_link_debug(link, "Remembering foreign neighbor: %s->%s",
-                                               strnull(addr_str), strnull(lladdr_str));
-                }
-
-                break;
-
-        case RTM_DELNEIGH:
-                if (neighbor) {
-                        log_link_debug(link, "Forgetting neighbor: %s->%s",
-                                       strnull(addr_str), strnull(lladdr_str));
-                        (void) neighbor_free(neighbor);
-                } else
-                        log_link_debug(link, "Kernel removed a neighbor we don't remember: %s->%s, ignoring.",
-                                       strnull(addr_str), strnull(lladdr_str));
-
-                break;
-
-        default:
-                assert_not_reached("Received invalid RTNL message type");
-        }
-
-        return 1;
-}
-
-int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        _cleanup_free_ char *buf = NULL;
-        Manager *m = userdata;
-        Link *link = NULL;
-        uint16_t type;
-        unsigned char flags, prefixlen, scope;
-        union in_addr_union in_addr = IN_ADDR_NULL;
-        struct ifa_cacheinfo cinfo;
-        Address *address = NULL;
-        char valid_buf[FORMAT_TIMESPAN_MAX];
-        const char *valid_str = NULL;
-        int ifindex, family, r;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
-                if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: failed to receive address message, ignoring");
-
-                return 0;
-        }
-
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
-                log_warning("rtnl: received unexpected message type %u when processing address, ignoring.", type);
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
-                return 0;
-        } else if (ifindex <= 0) {
-                log_warning("rtnl: received address message with invalid ifindex %d, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = link_get(m, ifindex, &link);
-        if (r < 0 || !link) {
-                /* when enumerating we might be out of sync, but we will get the address again, so just
-                 * ignore it */
-                if (!m->enumerating)
-                        log_warning("rtnl: received address for link '%d' we don't know about, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_family(message, &family);
-        if (r < 0) {
-                log_link_warning(link, "rtnl: received address message without family, ignoring.");
-                return 0;
-        } else if (!IN_SET(family, AF_INET, AF_INET6)) {
-                log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", family);
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address message with invalid prefixlen, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_scope(message, &scope);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address message with invalid scope, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_flags(message, &flags);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
-                return 0;
-        }
-
-        switch (family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Received unsupported address family");
-        }
-
-        r = in_addr_to_string(family, &in_addr, &buf);
-        if (r < 0)
-                log_link_warning_errno(link, r, "Could not print address: %m");
-
-        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
-        if (r < 0 && r != -ENODATA) {
-                log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
-                return 0;
-        } else if (r >= 0 && cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
-                valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
-                                            cinfo.ifa_valid * USEC_PER_SEC,
-                                            USEC_PER_SEC);
-
-        (void) address_get(link, family, &in_addr, prefixlen, &address);
-
-        switch (type) {
-        case RTM_NEWADDR:
-                if (address)
-                        log_link_debug(link, "Remembering updated address: %s/%u (valid %s%s)",
-                                       strnull(buf), prefixlen,
-                                       valid_str ? "for " : "forever", strempty(valid_str));
-                else {
-                        /* An address appeared that we did not request */
-                        r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m",
-                                                       strnull(buf), prefixlen);
-                                return 0;
-                        } else
-                                log_link_debug(link, "Remembering foreign address: %s/%u (valid %s%s)",
-                                               strnull(buf), prefixlen,
-                                               valid_str ? "for " : "forever", strempty(valid_str));
-                }
-
-                /* address_update() logs internally, so we don't need to here. */
-                r = address_update(address, flags, scope, &cinfo);
-                if (r < 0)
-                        link_enter_failed(link);
-
-                break;
-
-        case RTM_DELADDR:
-                if (address) {
-                        log_link_debug(link, "Forgetting address: %s/%u (valid %s%s)",
-                                       strnull(buf), prefixlen,
-                                       valid_str ? "for " : "forever", strempty(valid_str));
-                        (void) address_drop(address);
-                } else
-                        log_link_debug(link, "Kernel removed an address we don't remember: %s/%u (valid %s%s), ignoring.",
-                                       strnull(buf), prefixlen,
-                                       valid_str ? "for " : "forever", strempty(valid_str));
-
-                break;
-
-        default:
-                assert_not_reached("Received invalid RTNL message type");
-        }
-
-        return 1;
-}
-
-static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        Manager *m = userdata;
-        Link *link = NULL;
-        NetDev *netdev = NULL;
-        uint16_t type;
-        const char *name;
-        int r, ifindex;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
-                if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
-
-                return 0;
-        }
-
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
-                log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
-                return 0;
-        }
-
-        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
-                return 0;
-        } else if (ifindex <= 0) {
-                log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
-                return 0;
-        }
-
-        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
-                return 0;
-        }
-
-        (void) link_get(m, ifindex, &link);
-        (void) netdev_get(m, name, &netdev);
-
-        switch (type) {
-        case RTM_NEWLINK:
-                if (!link) {
-                        /* link is new, so add it */
-                        r = link_add(m, message, &link);
-                        if (r < 0) {
-                                log_warning_errno(r, "Could not process new link message, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                if (netdev) {
-                        /* netdev exists, so make sure the ifindex matches */
-                        r = netdev_set_ifindex(netdev, message);
-                        if (r < 0) {
-                                log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                r = link_update(link, message);
-                if (r < 0) {
-                        log_warning_errno(r, "Could not process link message, ignoring: %m");
-                        return 0;
-                }
-
-                break;
-
-        case RTM_DELLINK:
-                link_drop(link);
-                netdev_drop(netdev);
-
-                break;
-
-        default:
-                assert_not_reached("Received link message with invalid RTNL message type.");
-        }
-
-        return 1;
-}
-
-int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
-        _cleanup_free_ char *from = NULL, *to = NULL;
-        RoutingPolicyRule *rule = NULL;
-        const char *iif = NULL, *oif = NULL;
-        uint32_t suppress_prefixlen;
-        Manager *m = userdata;
-        unsigned flags;
-        uint16_t type;
-        int r;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
-                if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
-
-                return 0;
-        }
-
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
-                log_warning("rtnl: received unexpected message type %u when processing rule, ignoring.", type);
-                return 0;
-        }
-
-        r = routing_policy_rule_new(&tmp);
-        if (r < 0) {
-                log_oom();
-                return 0;
-        }
-
-        r = sd_rtnl_message_get_family(message, &tmp->family);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
-                log_debug("rtnl: received rule message with invalid family %d, ignoring.", tmp->family);
-                return 0;
-        }
-
-        switch (tmp->family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, FRA_SRC, &tmp->from.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
-                        return 0;
-                } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
-                        if (r < 0) {
-                                log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                r = sd_netlink_message_read_in_addr(message, FRA_DST, &tmp->to.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
-                        return 0;
-                } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
-                        if (r < 0) {
-                                log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                break;
-
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &tmp->from.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
-                        return 0;
-                } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
-                        if (r < 0) {
-                                log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                r = sd_netlink_message_read_in6_addr(message, FRA_DST, &tmp->to.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
-                        return 0;
-                } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
-                        if (r < 0) {
-                                log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
-                                return 0;
-                        }
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Received rule message with unsupported address family");
-        }
-
-        r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
-                return 0;
-        }
-        tmp->invert_rule = flags & FIB_RULE_INVERT;
-
-        r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
-                return 0;
-        }
-        r = free_and_strdup(&tmp->iif, iif);
-        if (r < 0)
-                return log_oom();
-
-        r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
-                return 0;
-        }
-        r = free_and_strdup(&tmp->oif, oif);
-        if (r < 0)
-                return log_oom();
-
-        r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_PREFIXLEN, &suppress_prefixlen);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_PREFIXLEN attribute, ignoring: %m");
+        /* udev does not initialize devices inside containers, so we rely on them being already
+         * initialized before entering the container. */
+        if (path_is_read_only_fs("/sys") > 0)
                 return 0;
-        }
-        if (r >= 0)
-                tmp->suppress_prefixlen = (int) suppress_prefixlen;
 
-        (void) routing_policy_rule_get(m, tmp, &rule);
+        r = sd_device_monitor_new(&m->device_monitor);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize device monitor: %m");
 
-        if (DEBUG_LOGGING) {
-                (void) in_addr_to_string(tmp->family, &tmp->from, &from);
-                (void) in_addr_to_string(tmp->family, &tmp->to, &to);
-        }
+        r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
+        if (r < 0)
+                log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
 
-        switch (type) {
-        case RTM_NEWRULE:
-                if (rule)
-                        log_debug("Received remembered routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
-                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
-                else {
-                        log_debug("Remembering foreign routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
-                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
-                        r = routing_policy_rule_add_foreign(m, tmp, &rule);
-                        if (r < 0) {
-                                log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
-                                return 0;
-                        }
-                }
-                break;
-        case RTM_DELRULE:
-                if (rule) {
-                        log_debug("Forgetting routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
-                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
-                        routing_policy_rule_free(rule);
-                } else
-                        log_debug("Kernel removed a routing policy rule we don't remember: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32", ignoring.",
-                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
-                break;
+        r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
+        if (r < 0)
+                return log_error_errno(r, "Could not add device monitor filter: %m");
 
-        default:
-                assert_not_reached("Received invalid RTNL message type");
-        }
+        r = sd_device_monitor_attach_event(m->device_monitor, m->event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach event to device monitor: %m");
 
-        return 1;
+        r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to start device monitor: %m");
+
+        return 0;
 }
 
-int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        _cleanup_(nexthop_freep) NextHop *tmp = NULL;
-        _cleanup_free_ char *gateway = NULL;
-        NextHop *nexthop = NULL;
-        Manager *m = userdata;
+static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
         Link *link = NULL;
+        NetDev *netdev = NULL;
         uint16_t type;
-        int r;
+        const char *name;
+        int r, ifindex;
 
         assert(rtnl);
         assert(message);
@@ -1224,105 +273,74 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
         if (sd_netlink_message_is_error(message)) {
                 r = sd_netlink_message_get_errno(message);
                 if (r < 0)
-                        log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
+                        log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
 
                 return 0;
         }
 
         r = sd_netlink_message_get_type(message, &type);
         if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
                 return 0;
-        } else if (!IN_SET(type, RTM_NEWNEXTHOP, RTM_DELNEXTHOP)) {
-                log_warning("rtnl: received unexpected message type %u when processing nexthop, ignoring.", type);
+        } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
+                log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
                 return 0;
         }
 
-        r = nexthop_new(&tmp);
-        if (r < 0)
-                return log_oom();
-
-        r = sd_rtnl_message_get_family(message, &tmp->family);
+        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
         if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get nexthop family, ignoring: %m");
-                return 0;
-        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
-                log_debug("rtnl: received nexthop message with invalid family %d, ignoring.", tmp->family);
-                return 0;
-        }
-
-        switch (tmp->family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, NHA_GATEWAY, &tmp->gw.in);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
-                        return 0;
-                }
-                break;
-
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, NHA_GATEWAY, &tmp->gw.in6);
-                if (r < 0 && r != -ENODATA) {
-                        log_warning_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
-                        return 0;
-                }
-                break;
-
-        default:
-                assert_not_reached("Received rule message with unsupported address family");
-        }
-
-        r = sd_netlink_message_read_u32(message, NHA_ID, &tmp->id);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get NHA_ID attribute, ignoring: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_u32(message, NHA_OIF, &tmp->oif);
-        if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
+                log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
                 return 0;
-        } else if (tmp->oif <= 0) {
-                log_warning("rtnl: received nexthop message with invalid ifindex %d, ignoring.", tmp->oif);
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
                 return 0;
         }
 
-        r = link_get(m, tmp->oif, &link);
-        if (r < 0 || !link) {
-                if (!m->enumerating)
-                        log_warning("rtnl: received nexthop message for link (%d) we do not know about, ignoring", tmp->oif);
+        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
                 return 0;
         }
 
-        (void) nexthop_get(link, tmp, &nexthop);
-
-        if (DEBUG_LOGGING)
-                (void) in_addr_to_string(tmp->family, &tmp->gw, &gateway);
+        (void) link_get(m, ifindex, &link);
+        (void) netdev_get(m, name, &netdev);
 
         switch (type) {
-        case RTM_NEWNEXTHOP:
-                if (nexthop)
-                        log_link_debug(link, "Received remembered nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
-                else {
-                        log_link_debug(link, "Remembering foreign nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
-                        r = nexthop_add_foreign(link, tmp, &nexthop);
+        case RTM_NEWLINK:
+                if (!link) {
+                        /* link is new, so add it */
+                        r = link_add(m, message, &link);
+                        if (r < 0) {
+                                log_warning_errno(r, "Could not process new link message, ignoring: %m");
+                                return 0;
+                        }
+                }
+
+                if (netdev) {
+                        /* netdev exists, so make sure the ifindex matches */
+                        r = netdev_set_ifindex(netdev, message);
                         if (r < 0) {
-                                log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m");
+                                log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
                                 return 0;
                         }
                 }
+
+                r = link_update(link, message);
+                if (r < 0) {
+                        log_warning_errno(r, "Could not process link message, ignoring: %m");
+                        return 0;
+                }
+
                 break;
-        case RTM_DELNEXTHOP:
-                if (nexthop) {
-                        log_link_debug(link, "Forgetting nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
-                        nexthop_free(nexthop);
-                } else
-                        log_link_debug(link, "Kernel removed a nexthop we don't remember: %s, oif: %d, id: %d, ignoring.",
-                                       strna(gateway), tmp->oif, tmp->id);
+
+        case RTM_DELLINK:
+                link_drop(link);
+                netdev_drop(netdev);
+
                 break;
 
         default:
-                assert_not_reached("Received invalid RTNL message type");
+                assert_not_reached("Received link message with invalid RTNL message type.");
         }
 
         return 1;
@@ -1393,51 +411,51 @@ static int manager_connect_rtnl(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
+        r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
+        r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
         if (r < 0)
                 return r;
 
@@ -1824,7 +842,7 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
-        r = setup_default_address_pool(m);
+        r = address_pool_setup_default(m);
         if (r < 0)
                 return r;
 
@@ -1838,7 +856,6 @@ int manager_new(Manager **ret) {
 }
 
 void manager_free(Manager *m) {
-        AddressPool *pool;
         Link *link;
 
         if (!m)
@@ -1847,7 +864,7 @@ void manager_free(Manager *m) {
         free(m->state_file);
 
         HASHMAP_FOREACH(link, m->links)
-                (void) link_stop_clients(link, true);
+                (void) link_stop_engines(link, true);
 
         m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
         m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
@@ -1861,8 +878,7 @@ void manager_free(Manager *m) {
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
 
-        while ((pool = m->address_pools))
-                address_pool_free(pool);
+        ordered_set_free_free(m->address_pools);
 
         /* routing_policy_rule_free() access m->rules and m->rules_foreign.
          * So, it is necessary to set NULL after the sets are freed. */
@@ -1870,6 +886,9 @@ void manager_free(Manager *m) {
         m->rules_foreign = set_free(m->rules_foreign);
         set_free(m->rules_saved);
 
+        m->routes = set_free(m->routes);
+        m->routes_foreign = set_free(m->routes_foreign);
+
         sd_netlink_unref(m->rtnl);
         sd_netlink_unref(m->genl);
         sd_resolve_unref(m->resolve);
@@ -1932,33 +951,41 @@ bool manager_should_reload(Manager *m) {
         return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false);
 }
 
-int manager_rtnl_enumerate_links(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *link;
+static int manager_enumerate_internal(
+                Manager *m,
+                sd_netlink_message *req,
+                int (*process)(sd_netlink *, sd_netlink_message *, Manager *),
+                const char *name) {
+
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
         int r;
 
         assert(m);
         assert(m->rtnl);
-
-        r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
-        if (r < 0)
-                return r;
+        assert(req);
+        assert(process);
 
         r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
         r = sd_netlink_call(m->rtnl, req, 0, &reply);
-        if (r < 0)
+        if (r < 0) {
+                if (r == -EOPNOTSUPP && name) {
+                        log_debug_errno(r, "%s are not supported by the kernel. Ignoring.", name);
+                        return 0;
+                }
+
                 return r;
+        }
 
-        for (link = reply; link; link = sd_netlink_message_next(link)) {
+        for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
                 int k;
 
                 m->enumerating = true;
 
-                k = manager_rtnl_process_link(m->rtnl, link, m);
-                if (k < 0)
+                k = process(m->rtnl, reply_one, m);
+                if (k < 0 && r >= 0)
                         r = k;
 
                 m->enumerating = false;
@@ -1967,44 +994,36 @@ int manager_rtnl_enumerate_links(Manager *m) {
         return r;
 }
 
-int manager_rtnl_enumerate_addresses(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *addr;
+static int manager_enumerate_links(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(m);
         assert(m->rtnl);
 
-        r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_call(m->rtnl, req, 0, &reply);
+        r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
         if (r < 0)
                 return r;
 
-        for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
-                int k;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_link, NULL);
+}
 
-                m->enumerating = true;
+static int manager_enumerate_addresses(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
 
-                k = manager_rtnl_process_address(m->rtnl, addr, m);
-                if (k < 0)
-                        r = k;
+        assert(m);
+        assert(m->rtnl);
 
-                m->enumerating = false;
-        }
+        r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
+        if (r < 0)
+                return r;
 
-        return r;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_address, NULL);
 }
 
-int manager_rtnl_enumerate_neighbors(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *neigh;
+static int manager_enumerate_neighbors(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(m);
@@ -2014,32 +1033,11 @@ int manager_rtnl_enumerate_neighbors(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_call(m->rtnl, req, 0, &reply);
-        if (r < 0)
-                return r;
-
-        for (neigh = reply; neigh; neigh = sd_netlink_message_next(neigh)) {
-                int k;
-
-                m->enumerating = true;
-
-                k = manager_rtnl_process_neighbor(m->rtnl, neigh, m);
-                if (k < 0)
-                        r = k;
-
-                m->enumerating = false;
-        }
-
-        return r;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_neighbor, NULL);
 }
 
-int manager_rtnl_enumerate_routes(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *route;
+static int manager_enumerate_routes(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(m);
@@ -2052,32 +1050,11 @@ int manager_rtnl_enumerate_routes(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_call(m->rtnl, req, 0, &reply);
-        if (r < 0)
-                return r;
-
-        for (route = reply; route; route = sd_netlink_message_next(route)) {
-                int k;
-
-                m->enumerating = true;
-
-                k = manager_rtnl_process_route(m->rtnl, route, m);
-                if (k < 0)
-                        r = k;
-
-                m->enumerating = false;
-        }
-
-        return r;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_route, NULL);
 }
 
-int manager_rtnl_enumerate_rules(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *rule;
+static int manager_enumerate_rules(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(m);
@@ -2087,38 +1064,11 @@ int manager_rtnl_enumerate_rules(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_call(m->rtnl, req, 0, &reply);
-        if (r < 0) {
-                if (r == -EOPNOTSUPP) {
-                        log_debug("FIB Rules are not supported by the kernel. Ignoring.");
-                        return 0;
-                }
-
-                return r;
-        }
-
-        for (rule = reply; rule; rule = sd_netlink_message_next(rule)) {
-                int k;
-
-                m->enumerating = true;
-
-                k = manager_rtnl_process_rule(m->rtnl, rule, m);
-                if (k < 0)
-                        r = k;
-
-                m->enumerating = false;
-        }
-
-        return r;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_rule, "Routing policy rules");
 }
 
-int manager_rtnl_enumerate_nexthop(Manager *m) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *nexthop;
+static int manager_enumerate_nexthop(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(m);
@@ -2128,51 +1078,35 @@ int manager_rtnl_enumerate_nexthop(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_call(m->rtnl, req, 0, &reply);
-        if (r < 0) {
-                if (r == -EOPNOTSUPP) {
-                        log_debug("Nexthop are not supported by the kernel. Ignoring.");
-                        return 0;
-                }
-
-                return r;
-        }
-
-        for (nexthop = reply; nexthop; nexthop = sd_netlink_message_next(nexthop)) {
-                int k;
-
-                m->enumerating = true;
+        return manager_enumerate_internal(m, req, manager_rtnl_process_nexthop, "Nexthop rules");
+}
 
-                k = manager_rtnl_process_nexthop(m->rtnl, nexthop, m);
-                if (k < 0)
-                        r = k;
+int manager_enumerate(Manager *m) {
+        int r;
 
-                m->enumerating = false;
-        }
+        r = manager_enumerate_links(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate links: %m");
 
-        return r;
-}
+        r = manager_enumerate_addresses(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate addresses: %m");
 
-int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
-        AddressPool *p;
-        int r;
+        r = manager_enumerate_neighbors(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate neighbors: %m");
 
-        assert(m);
-        assert(prefixlen > 0);
-        assert(found);
+        r = manager_enumerate_routes(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate routes: %m");
 
-        LIST_FOREACH(address_pools, p, m->address_pools) {
-                if (p->family != family)
-                        continue;
+        r = manager_enumerate_rules(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate routing policy rules: %m");
 
-                r = address_pool_acquire(p, prefixlen, found);
-                if (r != 0)
-                        return r;
-        }
+        r = manager_enumerate_nexthop(m);
+        if (r < 0)
+                return log_error_errno(r, "Could not enumerate nexthop rules: %m");
 
         return 0;
 }
@@ -2313,51 +1247,3 @@ int manager_set_timezone(Manager *m, const char *tz) {
 
         return 0;
 }
-
-int manager_request_product_uuid(Manager *m, Link *link) {
-        int r;
-
-        assert(m);
-
-        if (m->has_product_uuid)
-                return 0;
-
-        log_debug("Requesting product UUID");
-
-        if (link) {
-                DUID *duid;
-
-                assert_se(duid = link_get_duid(link));
-
-                r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
-                if (r < 0)
-                        return log_oom();
-                if (r > 0)
-                        link_ref(link);
-
-                r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid);
-                if (r < 0)
-                        return log_oom();
-        }
-
-        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
-                log_debug("Not connected to system bus, requesting product UUID later.");
-                return 0;
-        }
-
-        r = sd_bus_call_method_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.hostname1",
-                        "/org/freedesktop/hostname1",
-                        "org.freedesktop.hostname1",
-                        "GetProductUUID",
-                        get_product_uuid_handler,
-                        m,
-                        "b",
-                        false);
-        if (r < 0)
-                return log_warning_errno(r, "Failed to get product UUID: %m");
-
-        return 0;
-}
index 255a0d965f9105be47429fbe8a80c633c0fe4160..ac7de58c649a8ee34dc27d932426903aceaa1256 100644 (file)
 
 #include "dhcp-identifier.h"
 #include "hashmap.h"
-#include "list.h"
-#include "time-util.h"
-
-#include "networkd-address-pool.h"
 #include "networkd-link.h"
 #include "networkd-network.h"
+#include "ordered-set.h"
+#include "set.h"
+#include "time-util.h"
 
 struct Manager {
         sd_netlink *rtnl;
@@ -45,7 +44,7 @@ struct Manager {
         OrderedHashmap *networks;
         Hashmap *dhcp6_prefixes;
         Set *dhcp6_pd_prefixes;
-        LIST_HEAD(AddressPool, address_pools);
+        OrderedSet *address_pools;
 
         usec_t network_dirs_ts_usec;
 
@@ -62,6 +61,10 @@ struct Manager {
         Set *rules_foreign;
         Set *rules_saved;
 
+        /* Manager stores routes without RTA_OIF attribute. */
+        Set *routes;
+        Set *routes_foreign;
+
         /* For link speed meter*/
         bool use_speed_meter;
         sd_event_source *speed_meter_event_source;
@@ -82,27 +85,13 @@ int manager_start(Manager *m);
 int manager_load_config(Manager *m);
 bool manager_should_reload(Manager *m);
 
-int manager_rtnl_enumerate_links(Manager *m);
-int manager_rtnl_enumerate_addresses(Manager *m);
-int manager_rtnl_enumerate_neighbors(Manager *m);
-int manager_rtnl_enumerate_routes(Manager *m);
-int manager_rtnl_enumerate_rules(Manager *m);
-int manager_rtnl_enumerate_nexthop(Manager *m);
-
-int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
-int manager_rtnl_process_neighbor(sd_netlink *nl, sd_netlink_message *message, void *userdata);
-int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
-int manager_rtnl_process_rule(sd_netlink *nl, sd_netlink_message *message, void *userdata);
-int manager_rtnl_process_nexthop(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+int manager_enumerate(Manager *m);
 
 void manager_dirty(Manager *m);
 
-int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);
-
 Link* manager_find_uplink(Manager *m, Link *exclude);
 
 int manager_set_hostname(Manager *m, const char *hostname);
 int manager_set_timezone(Manager *m, const char *timezone);
-int manager_request_product_uuid(Manager *m, Link *link);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
index 542ba75ad0f8ab51a4218730f6f74c5911b7fb72..bca3e620dd4528597cfbc2a770f355ec04a3b99d 100644 (file)
@@ -3,13 +3,32 @@
 #include <net/if.h>
 
 #include "netlink-util.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-mdb.h"
+#include "networkd-network.h"
 #include "string-util.h"
 #include "vlan-util.h"
 
 #define STATIC_MDB_ENTRIES_PER_NETWORK_MAX 1024U
 
+/* remove MDB entry. */
+MdbEntry *mdb_entry_free(MdbEntry *mdb_entry) {
+        if (!mdb_entry)
+                return NULL;
+
+        if (mdb_entry->network) {
+                assert(mdb_entry->section);
+                hashmap_remove(mdb_entry->network->mdb_entries_by_section, mdb_entry->section);
+        }
+
+        network_config_section_free(mdb_entry->section);
+
+        return mfree(mdb_entry);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
+
 /* create a new MDB entry or get an existing one. */
 static int mdb_entry_new_static(
                 Network *network,
@@ -23,22 +42,21 @@ static int mdb_entry_new_static(
 
         assert(network);
         assert(ret);
-        assert(!!filename == (section_line > 0));
+        assert(filename);
+        assert(section_line > 0);
 
-        /* search entry in hashmap first. */
-        if (filename) {
-                r = network_config_section_new(filename, section_line, &n);
-                if (r < 0)
-                        return r;
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
-                if (mdb_entry) {
-                        *ret = TAKE_PTR(mdb_entry);
-                        return 0;
-                }
+        /* search entry in hashmap first. */
+        mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
+        if (mdb_entry) {
+                *ret = TAKE_PTR(mdb_entry);
+                return 0;
         }
 
-        if (network->n_static_mdb_entries >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
+        if (hashmap_size(network->mdb_entries_by_section) >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
                 return -E2BIG;
 
         /* allocate space for an MDB entry. */
@@ -49,48 +67,22 @@ static int mdb_entry_new_static(
         /* init MDB structure. */
         *mdb_entry = (MdbEntry) {
                 .network = network,
+                .section = TAKE_PTR(n),
         };
 
-        LIST_PREPEND(static_mdb_entries, network->static_mdb_entries, mdb_entry);
-        network->n_static_mdb_entries++;
-
-        if (filename) {
-                mdb_entry->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry);
+        if (r < 0)
+                return r;
 
         /* return allocated MDB structure. */
         *ret = TAKE_PTR(mdb_entry);
-
         return 0;
 }
 
-/* remove and MDB entry. */
-MdbEntry *mdb_entry_free(MdbEntry *mdb_entry) {
-        if (!mdb_entry)
-                return NULL;
-
-        if (mdb_entry->network) {
-                LIST_REMOVE(static_mdb_entries, mdb_entry->network->static_mdb_entries, mdb_entry);
-                assert(mdb_entry->network->n_static_mdb_entries > 0);
-                mdb_entry->network->n_static_mdb_entries--;
-
-                if (mdb_entry->section)
-                        hashmap_remove(mdb_entry->network->mdb_entries_by_section, mdb_entry->section);
-        }
-
-        network_config_section_free(mdb_entry->section);
-
-        return mfree(mdb_entry);
-}
-
 static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -212,7 +204,7 @@ int link_set_bridge_mdb(Link *link) {
         if (!link->network)
                 return 0;
 
-        if (LIST_IS_EMPTY(link->network->static_mdb_entries))
+        if (hashmap_isempty(link->network->mdb_entries_by_section))
                 goto finish;
 
         if (!link_has_carrier(link))
@@ -236,7 +228,7 @@ int link_set_bridge_mdb(Link *link) {
                 goto finish;
         }
 
-        LIST_FOREACH(static_mdb_entries, mdb_entry, link->network->static_mdb_entries) {
+        HASHMAP_FOREACH(mdb_entry, link->network->mdb_entries_by_section) {
                 r = mdb_entry_configure(link, mdb_entry);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
@@ -253,6 +245,49 @@ finish:
         return 0;
 }
 
+static int mdb_entry_verify(MdbEntry *mdb_entry) {
+        if (section_is_invalid(mdb_entry->section))
+                return -EINVAL;
+
+        if (mdb_entry->family == AF_UNSPEC)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
+                                         "Ignoring [BridgeMDB] section from line %u.",
+                                         mdb_entry->section->filename, mdb_entry->section->line);
+
+        if (!in_addr_is_multicast(mdb_entry->family, &mdb_entry->group_addr))
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: MulticastGroupAddress= is not a multicast address. "
+                                         "Ignoring [BridgeMDB] section from line %u.",
+                                         mdb_entry->section->filename, mdb_entry->section->line);
+
+        if (mdb_entry->family == AF_INET) {
+                if (in4_addr_is_local_multicast(&mdb_entry->group_addr.in))
+                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                 "%s: MulticastGroupAddress= is a local multicast address. "
+                                                 "Ignoring [BridgeMDB] section from line %u.",
+                                                 mdb_entry->section->filename, mdb_entry->section->line);
+        } else {
+                if (in6_addr_is_link_local_all_nodes(&mdb_entry->group_addr.in6))
+                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                 "%s: MulticastGroupAddress= is the multicast all nodes address. "
+                                                 "Ignoring [BridgeMDB] section from line %u.",
+                                                 mdb_entry->section->filename, mdb_entry->section->line);
+        }
+
+        return 0;
+}
+
+void network_drop_invalid_mdb_entries(Network *network) {
+        MdbEntry *mdb_entry;
+
+        assert(network);
+
+        HASHMAP_FOREACH(mdb_entry, network->mdb_entries_by_section)
+                if (mdb_entry_verify(mdb_entry) < 0)
+                        mdb_entry_free(mdb_entry);
+}
+
 /* parse the VLAN Id from config files. */
 int config_parse_mdb_vlan_id(
                 const char *unit,
@@ -328,36 +363,3 @@ int config_parse_mdb_group_address(
 
         return 0;
 }
-
-int mdb_entry_verify(MdbEntry *mdb_entry) {
-        if (section_is_invalid(mdb_entry->section))
-                return -EINVAL;
-
-        if (mdb_entry->family == AF_UNSPEC)
-                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
-                                         "%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
-                                         "Ignoring [BridgeMDB] section from line %u.",
-                                         mdb_entry->section->filename, mdb_entry->section->line);
-
-        if (!in_addr_is_multicast(mdb_entry->family, &mdb_entry->group_addr))
-                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
-                                         "%s: MulticastGroupAddress= is not a multicast address. "
-                                         "Ignoring [BridgeMDB] section from line %u.",
-                                         mdb_entry->section->filename, mdb_entry->section->line);
-
-        if (mdb_entry->family == AF_INET) {
-                if (in4_addr_is_local_multicast(&mdb_entry->group_addr.in))
-                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                 "%s: MulticastGroupAddress= is a local multicast address. "
-                                                 "Ignoring [BridgeMDB] section from line %u.",
-                                                 mdb_entry->section->filename, mdb_entry->section->line);
-        } else {
-                if (in6_addr_is_link_local_all_nodes(&mdb_entry->group_addr.in6))
-                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                 "%s: MulticastGroupAddress= is the multicast all nodes address. "
-                                                 "Ignoring [BridgeMDB] section from line %u.",
-                                                 mdb_entry->section->filename, mdb_entry->section->line);
-        }
-
-        return 0;
-}
index d46ab4a50e0ecee0d6490508aeb40cf6e559eca2..563a9e6d994a8cbb94e2f95c946c578501eabeac 100644 (file)
@@ -1,32 +1,29 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <inttypes.h>
+
 #include "conf-parser.h"
-#include "list.h"
-#include "macro.h"
+#include "in-addr-util.h"
 #include "networkd-util.h"
 
 typedef struct Network Network;
-typedef struct MdbEntry MdbEntry;
 typedef struct Link Link;
-typedef struct NetworkConfigSection NetworkConfigSection;
 
-struct MdbEntry {
+typedef struct MdbEntry {
         Network *network;
         NetworkConfigSection *section;
 
         int family;
         union in_addr_union group_addr;
         uint16_t vlan_id;
+} MdbEntry;
 
-        LIST_FIELDS(MdbEntry, static_mdb_entries);
-};
-
-int mdb_entry_verify(MdbEntry *mdb_entry);
 MdbEntry *mdb_entry_free(MdbEntry *mdb_entry);
-int link_set_bridge_mdb(Link *link);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
+void network_drop_invalid_mdb_entries(Network *network);
+
+int link_set_bridge_mdb(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id);
index 68a66649f027e9a853476649e1fe133686d7a50b..6fde8fe239259b4650d4939edbab70cfcd65f5f2 100644 (file)
@@ -3,16 +3,17 @@
   Copyright © 2014 Intel Corporation. All rights reserved.
 ***/
 
-#include <netinet/icmp6.h>
 #include <arpa/inet.h>
+#include <netinet/icmp6.h>
+#include <linux/if.h>
 
 #include "sd-ndisc.h"
 
 #include "missing_network.h"
+#include "networkd-address.h"
 #include "networkd-dhcp6.h"
 #include "networkd-manager.h"
 #include "networkd-ndisc.h"
-#include "networkd-route.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 
 #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
 
+bool link_ipv6_accept_ra_enabled(Link *link) {
+        assert(link);
+
+        if (!socket_ipv6_is_supported())
+                return false;
+
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        if (!link_ipv6ll_enabled(link))
+                return false;
+
+        assert(link->network->ipv6_accept_ra >= 0);
+        return link->network->ipv6_accept_ra;
+}
+
+void network_adjust_ipv6_accept_ra(Network *network) {
+        assert(network);
+
+        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
+                if (network->ipv6_accept_ra > 0)
+                        log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link local addressing is disabled or not supported. "
+                                    "Disabling IPv6AcceptRA=.", network->filename);
+                network->ipv6_accept_ra = false;
+        }
+
+        if (network->ipv6_accept_ra < 0)
+                /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
+                network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
+}
+
 static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
 
 static int ndisc_address_callback(Address *address) {
@@ -131,7 +166,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
 
         SET_FOREACH(nr, link->ndisc_routes)
                 if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
-                        k = route_remove(nr->route, link, NULL);
+                        k = route_remove(nr->route, NULL, link, NULL);
                         if (k < 0)
                                 r = k;
                 }
@@ -368,7 +403,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
                         return 1;
                 }
 
-                r = link_request_set_routes(link);
+                r = link_set_routes(link);
                 if (r < 0) {
                         link_enter_failed(link);
                         return 1;
@@ -429,7 +464,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         union in_addr_union gateway;
         uint16_t lifetime;
         unsigned preference;
-        uint32_t mtu;
+        uint32_t table, mtu;
         usec_t time_now;
         int r;
 
@@ -472,15 +507,18 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         else if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get default router MTU from RA: %m");
 
+        table = link_get_ipv6_accept_ra_route_table(link);
+
         r = route_new(&route);
         if (r < 0)
                 return log_oom();
 
         route->family = AF_INET6;
-        route->table = link_get_ipv6_accept_ra_route_table(link);
+        route->table = table;
         route->priority = link->network->dhcp6_route_metric;
         route->protocol = RTPROT_RA;
         route->pref = preference;
+        route->gw_family = AF_INET6;
         route->gw = gateway;
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
         route->mtu = mtu;
@@ -490,14 +528,25 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not set default route: %m");
 
         Route *route_gw;
-        LIST_FOREACH(routes, route_gw, link->network->static_routes) {
-                if (!route_gw->gateway_from_dhcp)
+        HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
+                if (!route_gw->gateway_from_dhcp_or_ra)
                         continue;
 
-                if (route_gw->family != AF_INET6)
+                if (route_gw->gw_family != AF_INET6)
                         continue;
 
                 route_gw->gw = gateway;
+                if (!route_gw->table_set)
+                        route_gw->table = table;
+                if (!route_gw->priority_set)
+                        route_gw->priority = link->network->dhcp6_route_metric;
+                if (!route_gw->protocol_set)
+                        route_gw->protocol = RTPROT_RA;
+                if (!route_gw->pref_set)
+                        route->pref = preference;
+                route_gw->lifetime = time_now + lifetime * USEC_PER_SEC;
+                if (route_gw->mtu == 0)
+                        route_gw->mtu = mtu;
 
                 r = ndisc_route_configure(route_gw, link, rt);
                 if (r < 0)
@@ -691,8 +740,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         SET_FOREACH(a, addresses) {
                 Address *existing_address;
 
+                address->in_addr.in6 = *a;
+
                 /* see RFC4862 section 5.5.3.e */
-                r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
+                r = address_get(link, address, &existing_address);
                 if (r > 0) {
                         lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
                         if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
@@ -709,8 +760,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 if (address->cinfo.ifa_valid == 0)
                         continue;
 
-                address->in_addr.in6 = *a;
-
                 r = ndisc_address_configure(address, link, rt);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
@@ -807,6 +856,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         route->protocol = RTPROT_RA;
         route->pref = preference;
         route->gw.in6 = gateway;
+        route->gw_family = AF_INET6;
         route->dst_prefixlen = prefixlen;
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
 
@@ -1133,9 +1183,9 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
         else {
                 log_link_debug(link, "Setting SLAAC addresses.");
 
-                /* address_handler calls link_request_set_routes() and link_request_set_nexthop().
-                 * Before they are called, the related flags must be cleared. Otherwise, the link
-                 * becomes configured state before routes are configured. */
+                /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
+                 * called, the related flags must be cleared. Otherwise, the link becomes configured
+                 * state before routes are configured. */
                 link->static_routes_configured = false;
                 link->static_nexthops_configured = false;
         }
@@ -1194,13 +1244,18 @@ int ndisc_configure(Link *link) {
 
         assert(link);
 
-        r = sd_ndisc_new(&link->ndisc);
-        if (r < 0)
-                return r;
+        if (!link_ipv6_accept_ra_enabled(link))
+                return 0;
 
-        r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
-        if (r < 0)
-                return r;
+        if (!link->ndisc) {
+                r = sd_ndisc_new(&link->ndisc);
+                if (r < 0)
+                        return r;
+
+                r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
+                if (r < 0)
+                        return r;
+        }
 
         r = sd_ndisc_set_mac(link->ndisc, &link->mac);
         if (r < 0)
index 927f555bc61014de6ff0fc96f550839cfbd4f03c..4e9a704995f84a92212e204b28d57ccfda44f9df 100644 (file)
@@ -69,6 +69,10 @@ static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
         return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
 }
 
+bool link_ipv6_accept_ra_enabled(Link *link);
+
+void network_adjust_ipv6_accept_ra(Network *network);
+
 int ndisc_configure(Link *link);
 void ndisc_vacuum(Link *link);
 void ndisc_flush(Link *link);
index 09ddb9c8a56b809db09ba702d404efc5cac8cfed..b553f1707ecfb45e8ce05843f4952fc8ea2df54e 100644 (file)
@@ -1,29 +1,21 @@
 /* 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"
+#include "networkd-network.h"
 #include "set.h"
 
-void neighbor_free(Neighbor *neighbor) {
+Neighbor *neighbor_free(Neighbor *neighbor) {
         if (!neighbor)
-                return;
+                return NULL;
 
         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);
+                assert(neighbor->section);
+                hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
         }
 
         network_config_section_free(neighbor->section);
@@ -33,9 +25,11 @@ void neighbor_free(Neighbor *neighbor) {
                 set_remove(neighbor->link->neighbors_foreign, neighbor);
         }
 
-        free(neighbor);
+        return mfree(neighbor);
 }
 
+DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
+
 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;
@@ -43,19 +37,17 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
 
         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;
+        assert(filename);
+        assert(section_line > 0);
 
-                neighbor = hashmap_get(network->neighbors_by_section, n);
-                if (neighbor) {
-                        *ret = TAKE_PTR(neighbor);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        neighbor = hashmap_get(network->neighbors_by_section, n);
+        if (neighbor) {
+                *ret = TAKE_PTR(neighbor);
+                return 0;
         }
 
         neighbor = new(Neighbor, 1);
@@ -65,28 +57,163 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
         *neighbor = (Neighbor) {
                 .network = network,
                 .family = AF_UNSPEC,
+                .section = TAKE_PTR(n),
         };
 
-        LIST_APPEND(neighbors, network->neighbors, neighbor);
-        network->n_neighbors++;
+        r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-        if (filename) {
-                neighbor->section = TAKE_PTR(n);
+        r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
+        if (r < 0)
+                return r;
 
-                r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
-                if (r < 0)
+        *ret = TAKE_PTR(neighbor);
+        return 0;
+}
+
+static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
+        assert(neighbor);
+
+        siphash24_compress(&neighbor->family, sizeof(neighbor->family), state);
+        siphash24_compress(&neighbor->lladdr_size, sizeof(neighbor->lladdr_size), state);
+
+        switch (neighbor->family) {
+        case AF_INET:
+        case AF_INET6:
+                /* Equality of neighbors are given by the pair (addr,lladdr) */
+                siphash24_compress(&neighbor->in_addr, FAMILY_ADDRESS_SIZE(neighbor->family), state);
+                break;
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                break;
+        }
+
+        siphash24_compress(&neighbor->lladdr, neighbor->lladdr_size, state);
+}
+
+static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
+        int r;
+
+        r = CMP(a->family, b->family);
+        if (r != 0)
+                return r;
+
+        r = CMP(a->lladdr_size, b->lladdr_size);
+        if (r != 0)
+                return r;
+
+        switch (a->family) {
+        case AF_INET:
+        case AF_INET6:
+                r = memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
+                if (r != 0)
                         return r;
+        }
+
+        return memcmp(&a->lladdr, &b->lladdr, a->lladdr_size);
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
+
+static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
+        Neighbor *existing;
+
+        assert(link);
+        assert(in);
+
+        existing = set_get(link->neighbors, in);
+        if (existing) {
+                if (ret)
+                        *ret = existing;
+                return 1;
+        }
+
+        existing = set_get(link->neighbors_foreign, in);
+        if (existing) {
+                if (ret)
+                        *ret = existing;
+                return 0;
+        }
+
+        return -ENOENT;
+}
+
+static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in, Neighbor **ret) {
+        _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
+        int r;
+
+        assert(link);
+        assert(neighbors);
+        assert(in);
 
-                r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
+        neighbor = new(Neighbor, 1);
+        if (!neighbor)
+                return -ENOMEM;
+
+        *neighbor = (Neighbor) {
+                .family = in->family,
+                .in_addr = in->in_addr,
+                .lladdr = in->lladdr,
+                .lladdr_size = in->lladdr_size,
+        };
+
+        r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EEXIST;
+
+        neighbor->link = link;
+
+        if (ret)
+                *ret = neighbor;
+
+        TAKE_PTR(neighbor);
+        return 0;
+}
+
+static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) {
+        Neighbor *neighbor;
+        int r;
+
+        r = neighbor_get(link, in, &neighbor);
+        if (r == -ENOENT) {
+                /* Neighbor doesn't exist, make a new one */
+                r = neighbor_add_internal(link, &link->neighbors, in, &neighbor);
+                if (r < 0)
+                        return r;
+        } else if (r == 0) {
+                /* Neighbor is foreign, claim it as recognized */
+                r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
                 if (r < 0)
                         return r;
-        }
 
-        *ret = TAKE_PTR(neighbor);
+                set_remove(link->neighbors_foreign, neighbor);
+        } else if (r == 1) {
+                /* Neighbor already exists */
+        } else
+                return r;
 
+        if (ret)
+                *ret = neighbor;
         return 0;
 }
 
+static int neighbor_add_foreign(Link *link, const Neighbor *in, Neighbor **ret) {
+        return neighbor_add_internal(link, &link->neighbors_foreign, in, ret);
+}
+
+static bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
+        if (n1 == n2)
+                return true;
+
+        if (!n1 || !n2)
+                return false;
+
+        return neighbor_compare_func(n1, n2) == 0;
+}
+
 static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -113,7 +240,7 @@ static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, L
         return 1;
 }
 
-int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
+static int neighbor_configure(Neighbor *neighbor, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -124,7 +251,7 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
         assert(link->manager->rtnl);
 
         r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
-                                          link->ifindex, neighbor->family);
+                                      link->ifindex, neighbor->family);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_NEWNEIGH message: %m");
 
@@ -144,7 +271,7 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_configure_handler,
+        r = netlink_call_async(link->manager->rtnl, NULL, req, neighbor_configure_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -152,13 +279,40 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
         link->neighbor_messages++;
         link_ref(link);
 
-        r = neighbor_add(link, neighbor->family, &neighbor->in_addr, &neighbor->lladdr, neighbor->lladdr_size, NULL);
+        r = neighbor_add(link, neighbor, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not add neighbor: %m");
 
         return 0;
 }
 
+int link_set_neighbors(Link *link) {
+        Neighbor *neighbor;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->state != _LINK_STATE_INVALID);
+
+        link->neighbors_configured = false;
+
+        HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
+                r = neighbor_configure(neighbor, link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not set neighbor: %m");
+        }
+
+        if (link->neighbor_messages == 0) {
+                link->neighbors_configured = true;
+                link_check_ready(link);
+        } else {
+                log_link_debug(link, "Setting neighbors");
+                link_set_state(link, LINK_STATE_CONFIGURING);
+        }
+
+        return 0;
+}
+
 static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -176,7 +330,7 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
         return 1;
 }
 
-int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
+static int neighbor_remove(Neighbor *neighbor, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -187,7 +341,7 @@ int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler
         assert(link->manager->rtnl);
 
         r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_DELNEIGH,
-                                          link->ifindex, neighbor->family);
+                                      link->ifindex, neighbor->family);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
 
@@ -195,7 +349,7 @@ int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_remove_handler,
+        r = netlink_call_async(link->manager->rtnl, NULL, req, neighbor_remove_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -205,158 +359,220 @@ int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler
         return 0;
 }
 
-static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
+static bool link_is_neighbor_configured(Link *link, Neighbor *neighbor) {
+        Neighbor *net_neighbor;
+
+        assert(link);
         assert(neighbor);
 
-        siphash24_compress(&neighbor->family, sizeof(neighbor->family), state);
-        siphash24_compress(&neighbor->lladdr_size, sizeof(neighbor->lladdr_size), state);
+        if (!link->network)
+                return false;
 
-        switch (neighbor->family) {
-        case AF_INET:
-        case AF_INET6:
-                /* Equality of neighbors are given by the pair (addr,lladdr) */
-                siphash24_compress(&neighbor->in_addr, FAMILY_ADDRESS_SIZE(neighbor->family), state);
-                break;
-        default:
-                /* treat any other address family as AF_UNSPEC */
-                break;
-        }
+        HASHMAP_FOREACH(net_neighbor, link->network->neighbors_by_section)
+                if (neighbor_equal(net_neighbor, neighbor))
+                        return true;
 
-        siphash24_compress(&neighbor->lladdr, neighbor->lladdr_size, state);
+        return false;
 }
 
-static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
+int link_drop_foreign_neighbors(Link *link) {
+        Neighbor *neighbor;
         int r;
 
-        r = CMP(a->family, b->family);
-        if (r != 0)
-                return r;
+        assert(link);
 
-        r = CMP(a->lladdr_size, b->lladdr_size);
-        if (r != 0)
-                return r;
+        SET_FOREACH(neighbor, link->neighbors_foreign)
+                if (link_is_neighbor_configured(link, neighbor)) {
+                        r = neighbor_add(link, neighbor, NULL);
+                        if (r < 0)
+                                return r;
+                } else {
+                        r = neighbor_remove(neighbor, link);
+                        if (r < 0)
+                                return r;
+                }
 
-        switch (a->family) {
-        case AF_INET:
-        case AF_INET6:
-                r = memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
-                if (r != 0)
-                        return r;
+        return 0;
+}
+
+int link_drop_neighbors(Link *link) {
+        Neighbor *neighbor;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(neighbor, link->neighbors) {
+                k = neighbor_remove(neighbor, link);
+                if (k < 0 && r >= 0)
+                        r = k;
         }
 
-        return memcmp(&a->lladdr, &b->lladdr, a->lladdr_size);
+        return r;
 }
 
-DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
-
-int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
-        Neighbor neighbor, *existing;
+static int manager_rtnl_process_neighbor_lladdr(sd_netlink_message *message, union lladdr_union *lladdr, size_t *size, char **str) {
+        int r;
 
-        assert(link);
-        assert(addr);
+        assert(message);
         assert(lladdr);
+        assert(size);
+        assert(str);
 
-        neighbor = (Neighbor) {
-                .family = family,
-                .in_addr = *addr,
-                .lladdr = *lladdr,
-                .lladdr_size = lladdr_size,
-        };
+        *str = NULL;
 
-        existing = set_get(link->neighbors, &neighbor);
-        if (existing) {
-                if (ret)
-                        *ret = existing;
-                return 1;
+        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in6), &lladdr->ip.in6);
+        if (r >= 0) {
+                *size = sizeof(lladdr->ip.in6);
+                if (in_addr_to_string(AF_INET6, &lladdr->ip, str) < 0)
+                        log_warning_errno(r, "Could not print lower address: %m");
+                return r;
         }
 
-        existing = set_get(link->neighbors_foreign, &neighbor);
-        if (existing) {
-                if (ret)
-                        *ret = existing;
-                return 0;
+        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->mac), &lladdr->mac);
+        if (r >= 0) {
+                *size = sizeof(lladdr->mac);
+                *str = new(char, ETHER_ADDR_TO_STRING_MAX);
+                if (!*str) {
+                        log_oom();
+                        return r;
+                }
+                ether_addr_to_string(&lladdr->mac, *str);
+                return r;
         }
 
-        return -ENOENT;
+        r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in), &lladdr->ip.in);
+        if (r >= 0) {
+                *size = sizeof(lladdr->ip.in);
+                if (in_addr_to_string(AF_INET, &lladdr->ip, str) < 0)
+                        log_warning_errno(r, "Could not print lower address: %m");
+                return r;
+        }
+
+        return r;
 }
 
-static int neighbor_add_internal(Link *link, Set **neighbors, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
-        _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
-        int r;
+int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
+        _cleanup_(neighbor_freep) Neighbor *tmp = NULL;
+        _cleanup_free_ char *addr_str = NULL, *lladdr_str = NULL;
+        Neighbor *neighbor = NULL;
+        uint16_t type, state;
+        int ifindex, r;
+        Link *link;
 
-        assert(link);
-        assert(neighbors);
-        assert(addr);
-        assert(lladdr);
+        assert(rtnl);
+        assert(message);
+        assert(m);
 
-        neighbor = new(Neighbor, 1);
-        if (!neighbor)
-                return -ENOMEM;
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
 
-        *neighbor = (Neighbor) {
-                .family = family,
-                .in_addr = *addr,
-                .lladdr = *lladdr,
-                .lladdr_size = lladdr_size,
-        };
+                return 0;
+        }
 
-        r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -EEXIST;
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(type, RTM_NEWNEIGH, RTM_DELNEIGH)) {
+                log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type);
+                return 0;
+        }
 
-        neighbor->link = link;
+        r = sd_rtnl_message_neigh_get_state(message, &state);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
+                return 0;
+        } else if (!FLAGS_SET(state, NUD_PERMANENT)) {
+                log_debug("rtnl: received non-static neighbor, ignoring.");
+                return 0;
+        }
 
-        if (ret)
-                *ret = neighbor;
-        TAKE_PTR(neighbor);
+        r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
+                return 0;
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex);
+                return 0;
+        }
 
-        return 0;
-}
+        r = link_get(m, ifindex, &link);
+        if (r < 0 || !link) {
+                /* when enumerating we might be out of sync, but we will get the neighbor again, so just
+                 * ignore it */
+                if (!m->enumerating)
+                        log_warning("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex);
+                return 0;
+        }
 
-int neighbor_add(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
-        Neighbor *neighbor;
-        int r;
+        tmp = new0(Neighbor, 1);
 
-        r = neighbor_get(link, family, addr, lladdr, lladdr_size, &neighbor);
-        if (r == -ENOENT) {
-                /* Neighbor doesn't exist, make a new one */
-                r = neighbor_add_internal(link, &link->neighbors, family, addr, lladdr, lladdr_size, &neighbor);
-                if (r < 0)
-                        return r;
-        } else if (r == 0) {
-                /* Neighbor is foreign, claim it as recognized */
-                r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
-                if (r < 0)
-                        return r;
+        r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
+        if (r < 0) {
+                log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
+                return 0;
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
+                return 0;
+        }
 
-                set_remove(link->neighbors_foreign, neighbor);
-        } else if (r == 1) {
-                /* Neighbor already exists */
-        } else
-                return r;
+        r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
+                return 0;
+        }
 
-        if (ret)
-                *ret = neighbor;
-        return 0;
-}
+        if (in_addr_to_string(tmp->family, &tmp->in_addr, &addr_str) < 0)
+                log_link_warning_errno(link, r, "Could not print address: %m");
 
-int neighbor_add_foreign(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
-        return neighbor_add_internal(link, &link->neighbors_foreign, family, addr, lladdr, lladdr_size, ret);
-}
+        r = manager_rtnl_process_neighbor_lladdr(message, &tmp->lladdr, &tmp->lladdr_size, &lladdr_str);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid lladdr, ignoring: %m");
+                return 0;
+        }
 
-bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
-        if (n1 == n2)
-                return true;
+        (void) neighbor_get(link, tmp, &neighbor);
+
+        switch (type) {
+        case RTM_NEWNEIGH:
+                if (neighbor)
+                        log_link_debug(link, "Received remembered neighbor: %s->%s",
+                                       strnull(addr_str), strnull(lladdr_str));
+                else {
+                        /* A neighbor appeared that we did not request */
+                        r = neighbor_add_foreign(link, tmp, NULL);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to remember foreign neighbor %s->%s, ignoring: %m",
+                                                       strnull(addr_str), strnull(lladdr_str));
+                                return 0;
+                        } else
+                                log_link_debug(link, "Remembering foreign neighbor: %s->%s",
+                                               strnull(addr_str), strnull(lladdr_str));
+                }
 
-        if (!n1 || !n2)
-                return false;
+                break;
 
-        return neighbor_compare_func(n1, n2) == 0;
+        case RTM_DELNEIGH:
+                if (neighbor) {
+                        log_link_debug(link, "Forgetting neighbor: %s->%s",
+                                       strnull(addr_str), strnull(lladdr_str));
+                        (void) neighbor_free(neighbor);
+                } else
+                        log_link_debug(link, "Kernel removed a neighbor we don't remember: %s->%s, ignoring.",
+                                       strnull(addr_str), strnull(lladdr_str));
+
+                break;
+
+        default:
+                assert_not_reached("Received invalid RTNL message type");
+        }
+
+        return 1;
 }
 
-int neighbor_section_verify(Neighbor *neighbor) {
+static int neighbor_section_verify(Neighbor *neighbor) {
         if (section_is_invalid(neighbor->section))
                 return -EINVAL;
 
@@ -375,6 +591,17 @@ int neighbor_section_verify(Neighbor *neighbor) {
         return 0;
 }
 
+void network_drop_invalid_neighbors(Network *network) {
+        Neighbor *neighbor;
+
+        assert(network);
+
+        HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
+                if (neighbor_section_verify(neighbor) < 0)
+                        neighbor_free(neighbor);
+}
+
+
 int config_parse_neighbor_address(
                 const char *unit,
                 const char *filename,
index 97ee1f6d73ea4931815dc7e7d431fdbbb6ddf475..bb403ef2da2e00c6613c92de91e40227daf5c6fc 100644 (file)
@@ -1,26 +1,25 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdbool.h>
+
 #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"
 #include "networkd-util.h"
 
+typedef Manager Manager;
+typedef Network Network;
+typedef Link Link;
+
 union lladdr_union {
         struct ether_addr mac;
         union in_addr_union ip;
 };
 
-struct Neighbor {
+typedef struct Neighbor {
         Network *network;
         Link *link;
         NetworkConfigSection *section;
@@ -29,23 +28,17 @@ struct Neighbor {
         union in_addr_union in_addr;
         union lladdr_union lladdr;
         size_t lladdr_size;
+} Neighbor;
 
-        LIST_FIELDS(Neighbor, neighbors);
-};
-
-void neighbor_free(Neighbor *neighbor);
-
-DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
+Neighbor *neighbor_free(Neighbor *neighbor);
 
-int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
-int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
+void network_drop_invalid_neighbors(Network *network);
 
-int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
-int neighbor_add(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
-int neighbor_add_foreign(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
-bool neighbor_equal(const Neighbor *n1, const Neighbor *n2);
+int link_set_neighbors(Link *link);
+int link_drop_neighbors(Link *link);
+int link_drop_foreign_neighbors(Link *link);
 
-int neighbor_section_verify(Neighbor *neighbor);
+int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_hwaddr);
index 1258203adf6889c815aefb531350ee34e5d55d9c..5cc9e3e8f6e47e6ab30b705815e1292a19ffa9a4 100644 (file)
@@ -6,15 +6,25 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
 #include "conf-parser.h"
 #include "netem.h"
 #include "network-internal.h"
+#include "networkd-address-label.h"
+#include "networkd-address.h"
 #include "networkd-can.h"
 #include "networkd-conf.h"
 #include "networkd-dhcp-common.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-dhcp4.h"
 #include "networkd-dhcp6.h"
+#include "networkd-fdb.h"
 #include "networkd-ipv4ll.h"
+#include "networkd-ipv6-proxy-ndp.h"
+#include "networkd-mdb.h"
 #include "networkd-ndisc.h"
 #include "networkd-network.h"
+#include "networkd-neighbor.h"
+#include "networkd-nexthop.h"
+#include "networkd-radv.h"
+#include "networkd-route.h"
+#include "networkd-routing-policy-rule.h"
 #include "networkd-sriov.h"
 #include "qdisc.h"
 #include "tclass.h"
@@ -116,16 +126,18 @@ Network.BindCarrier,                         config_parse_strv,
 Network.ConfigureWithoutCarrier,             config_parse_bool,                                        0,                             offsetof(Network, configure_without_carrier)
 Network.IgnoreCarrierLoss,                   config_parse_tristate,                                    0,                             offsetof(Network, ignore_carrier_loss)
 Network.KeepConfiguration,                   config_parse_keep_configuration,                          0,                             offsetof(Network, keep_configuration)
+Network.IPv6SendRA,                          config_parse_router_prefix_delegation,                    0,                             offsetof(Network, router_prefix_delegation)
+Network.DHCPv6PrefixDelegation,              config_parse_tristate,                                    0,                             offsetof(Network, dhcp6_pd)
 Address.Address,                             config_parse_address,                                     0,                             0
 Address.Peer,                                config_parse_address,                                     0,                             0
 Address.Broadcast,                           config_parse_broadcast,                                   0,                             0
 Address.Label,                               config_parse_label,                                       0,                             0
 Address.PreferredLifetime,                   config_parse_lifetime,                                    0,                             0
-Address.HomeAddress,                         config_parse_address_flags,                               0,                             0
-Address.ManageTemporaryAddress,              config_parse_address_flags,                               0,                             0
-Address.PrefixRoute,                         config_parse_address_flags,                               0,                             0 /* deprecated */
-Address.AddPrefixRoute,                      config_parse_address_flags,                               0,                             0
-Address.AutoJoin,                            config_parse_address_flags,                               0,                             0
+Address.HomeAddress,                         config_parse_address_flags,                               IFA_F_HOMEADDRESS,             0
+Address.ManageTemporaryAddress,              config_parse_address_flags,                               IFA_F_MANAGETEMPADDR,          0
+Address.PrefixRoute,                         config_parse_address_flags,                               IFA_F_NOPREFIXROUTE,           0 /* deprecated */
+Address.AddPrefixRoute,                      config_parse_address_flags,                               IFA_F_NOPREFIXROUTE,           0
+Address.AutoJoin,                            config_parse_address_flags,                               IFA_F_MCAUTOJOIN,              0
 Address.DuplicateAddressDetection,           config_parse_duplicate_address_detection,                 0,                             0
 Address.Scope,                               config_parse_address_scope,                               0,                             0
 IPv6AddressLabel.Prefix,                     config_parse_address_label_prefix,                        0,                             0
@@ -199,14 +211,14 @@ DHCPv4.SendRelease,                          config_parse_bool,
 DHCPv4.SendDecline,                          config_parse_bool,                                        0,                             offsetof(Network, dhcp_send_decline)
 DHCPv4.DenyList,                             config_parse_dhcp_acl_ip_address,                         0,                             0
 DHCPv4.AllowList,                            config_parse_dhcp_acl_ip_address,                         0,                             0
-DHCPv4.IPServiceType,                        config_parse_dhcp_ip_service_type,                        0,                             offsetof(Network, ip_service_type)
+DHCPv4.IPServiceType,                        config_parse_dhcp_ip_service_type,                        0,                             offsetof(Network, dhcp_ip_service_type)
 DHCPv4.SendOption,                           config_parse_dhcp_send_option,                            AF_INET,                       offsetof(Network, dhcp_client_send_options)
 DHCPv4.SendVendorOption,                     config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_client_send_vendor_options)
 DHCPv4.RouteMTUBytes,                        config_parse_mtu,                                         AF_INET,                       offsetof(Network, dhcp_route_mtu)
 DHCPv4.FallbackLeaseLifetimeSec,             config_parse_dhcp_fallback_lease_lifetime,                0,                             0
 DHCPv6.UseDNS,                               config_parse_dhcp_use_dns,                                0,                             0
 DHCPv6.UseNTP,                               config_parse_dhcp_use_ntp,                                0,                             0
-DHCPv6.RapidCommit,                          config_parse_bool,                                        0,                             offsetof(Network, rapid_commit)
+DHCPv6.RapidCommit,                          config_parse_bool,                                        0,                             offsetof(Network, dhcp6_rapid_commit)
 DHCPv6.MUDURL,                               config_parse_dhcp6_mud_url,                               0,                             0
 DHCPv6.RequestOptions,                       config_parse_dhcp_request_options,                        AF_INET6,                      0
 DHCPv6.UserClass,                            config_parse_dhcp_user_class,                             AF_INET6,                      offsetof(Network, dhcp6_user_class)
@@ -270,19 +282,19 @@ BridgeMDB.VLANId,                            config_parse_mdb_vlan_id,
 BridgeVLAN.PVID,                             config_parse_brvlan_pvid,                                 0,                             0
 BridgeVLAN.VLAN,                             config_parse_brvlan_vlan,                                 0,                             0
 BridgeVLAN.EgressUntagged,                   config_parse_brvlan_untagged,                             0,                             0
-Network.IPv6PrefixDelegation,                config_parse_router_prefix_delegation,                    0,                             offsetof(Network, router_prefix_delegation)
 DHCPv6PrefixDelegation.SubnetId,             config_parse_dhcp6_pd_subnet_id,                          0,                             offsetof(Network, dhcp6_pd_subnet_id)
+DHCPv6PrefixDelegation.Announce,             config_parse_bool,                                        0,                             offsetof(Network, dhcp6_pd_announce)
 DHCPv6PrefixDelegation.Assign,               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_pd_assign)
 DHCPv6PrefixDelegation.Token,                config_parse_dhcp6_pd_token,                              0,                             offsetof(Network, dhcp6_pd_token)
-IPv6PrefixDelegation.RouterLifetimeSec,      config_parse_sec,                                         0,                             offsetof(Network, router_lifetime_usec)
-IPv6PrefixDelegation.Managed,                config_parse_bool,                                        0,                             offsetof(Network, router_managed)
-IPv6PrefixDelegation.OtherInformation,       config_parse_bool,                                        0,                             offsetof(Network, router_other_information)
-IPv6PrefixDelegation.RouterPreference,       config_parse_router_preference,                           0,                             0
-IPv6PrefixDelegation.EmitDNS,                config_parse_bool,                                        0,                             offsetof(Network, router_emit_dns)
-IPv6PrefixDelegation.DNS,                    config_parse_radv_dns,                                    0,                             0
-IPv6PrefixDelegation.EmitDomains,            config_parse_bool,                                        0,                             offsetof(Network, router_emit_domains)
-IPv6PrefixDelegation.Domains,                config_parse_radv_search_domains,                         0,                             0
-IPv6PrefixDelegation.DNSLifetimeSec,         config_parse_sec,                                         0,                             offsetof(Network, router_dns_lifetime_usec)
+IPv6SendRA.RouterLifetimeSec,                config_parse_sec,                                         0,                             offsetof(Network, router_lifetime_usec)
+IPv6SendRA.Managed,                          config_parse_bool,                                        0,                             offsetof(Network, router_managed)
+IPv6SendRA.OtherInformation,                 config_parse_bool,                                        0,                             offsetof(Network, router_other_information)
+IPv6SendRA.RouterPreference,                 config_parse_router_preference,                           0,                             0
+IPv6SendRA.EmitDNS,                          config_parse_bool,                                        0,                             offsetof(Network, router_emit_dns)
+IPv6SendRA.DNS,                              config_parse_radv_dns,                                    0,                             0
+IPv6SendRA.EmitDomains,                      config_parse_bool,                                        0,                             offsetof(Network, router_emit_domains)
+IPv6SendRA.Domains,                          config_parse_radv_search_domains,                         0,                             0
+IPv6SendRA.DNSLifetimeSec,                   config_parse_sec,                                         0,                             offsetof(Network, router_dns_lifetime_usec)
 IPv6Prefix.Prefix,                           config_parse_prefix,                                      0,                             0
 IPv6Prefix.OnLink,                           config_parse_prefix_flags,                                0,                             0
 IPv6Prefix.AddressAutoconfiguration,         config_parse_prefix_flags,                                0,                             0
@@ -419,6 +431,16 @@ TrivialLinkEqualizer.Handle,                 config_parse_qdisc_handle,
 TrivialLinkEqualizer.Id,                     config_parse_trivial_link_equalizer_id,                   QDISC_KIND_TEQL,               0
 /* backwards compatibility: do not add new entries to this section */
 Network.IPv4LL,                              config_parse_ipv4ll,                                      0,                             offsetof(Network, link_local)
+Network.IPv6PrefixDelegation,                config_parse_router_prefix_delegation,                    0,                             offsetof(Network, router_prefix_delegation)
+IPv6PrefixDelegation.RouterLifetimeSec,      config_parse_sec,                                         0,                             offsetof(Network, router_lifetime_usec)
+IPv6PrefixDelegation.Managed,                config_parse_bool,                                        0,                             offsetof(Network, router_managed)
+IPv6PrefixDelegation.OtherInformation,       config_parse_bool,                                        0,                             offsetof(Network, router_other_information)
+IPv6PrefixDelegation.RouterPreference,       config_parse_router_preference,                           0,                             0
+IPv6PrefixDelegation.EmitDNS,                config_parse_bool,                                        0,                             offsetof(Network, router_emit_dns)
+IPv6PrefixDelegation.DNS,                    config_parse_radv_dns,                                    0,                             0
+IPv6PrefixDelegation.EmitDomains,            config_parse_bool,                                        0,                             offsetof(Network, router_emit_domains)
+IPv6PrefixDelegation.Domains,                config_parse_radv_search_domains,                         0,                             0
+IPv6PrefixDelegation.DNSLifetimeSec,         config_parse_sec,                                         0,                             offsetof(Network, router_dns_lifetime_usec)
 DHCPv4.BlackList,                            config_parse_dhcp_acl_ip_address,                         0,                             0
 DHCP.ClientIdentifier,                       config_parse_dhcp_client_identifier,                      0,                             offsetof(Network, dhcp_client_identifier)
 DHCP.UseDNS,                                 config_parse_dhcp_use_dns,                                0,                             0
@@ -442,7 +464,7 @@ DHCP.RouteTable,                             config_parse_section_route_table,
 DHCP.UseTimezone,                            config_parse_bool,                                        0,                             offsetof(Network, dhcp_use_timezone)
 DHCP.IAID,                                   config_parse_iaid,                                        0,                             0
 DHCP.ListenPort,                             config_parse_uint16,                                      0,                             offsetof(Network, dhcp_client_port)
-DHCP.RapidCommit,                            config_parse_bool,                                        0,                             offsetof(Network, rapid_commit)
+DHCP.RapidCommit,                            config_parse_bool,                                        0,                             offsetof(Network, dhcp6_rapid_commit)
 DHCP.ForceDHCPv6PDOtherInformation,          config_parse_bool,                                        0,                             offsetof(Network, dhcp6_force_pd_other_information)
 DHCPv4.UseDomainName,                        config_parse_dhcp_use_domains,                            0,                             offsetof(Network, dhcp_use_domains)
 DHCPv4.CriticalConnection,                   config_parse_tristate,                                    0,                             offsetof(Network, dhcp_critical)
index 49e6d62abb53688071a09050dba5f97d4067cdcb..426dd0a8f0bfc6dc206ee3e5b76a6c962328e0d0 100644 (file)
 #include "in-addr-util.h"
 #include "networkd-dhcp-server.h"
 #include "network-internal.h"
+#include "networkd-address-label.h"
+#include "networkd-address.h"
+#include "networkd-dhcp-common.h"
+#include "networkd-fdb.h"
 #include "networkd-manager.h"
+#include "networkd-mdb.h"
+#include "networkd-ndisc.h"
+#include "networkd-neighbor.h"
 #include "networkd-network.h"
+#include "networkd-nexthop.h"
+#include "networkd-radv.h"
+#include "networkd-routing-policy-rule.h"
 #include "networkd-sriov.h"
 #include "parse-util.h"
 #include "path-lookup.h"
@@ -148,19 +158,6 @@ static int network_resolve_stacked_netdevs(Network *network) {
 }
 
 int network_verify(Network *network) {
-        RoutePrefix *route_prefix, *route_prefix_next;
-        RoutingPolicyRule *rule, *rule_next;
-        Neighbor *neighbor, *neighbor_next;
-        AddressLabel *label, *label_next;
-        NextHop *nexthop, *nextnop_next;
-        Address *address, *address_next;
-        Prefix *prefix, *prefix_next;
-        Route *route, *route_next;
-        FdbEntry *fdb, *fdb_next;
-        MdbEntry *mdb, *mdb_next;
-        TrafficControl *tc;
-        SRIOV *sr_iov;
-
         assert(network);
         assert(network->filename);
 
@@ -193,63 +190,30 @@ int network_verify(Network *network) {
 
         if (network->bond) {
                 /* Bonding slave does not support addressing. */
-                if (network->ipv6_accept_ra > 0) {
-                        log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
-                                    network->filename);
-                        network->ipv6_accept_ra = 0;
-                }
                 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
                         log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
                                     network->filename);
                         network->link_local = ADDRESS_FAMILY_NO;
                 }
-                if (network->dhcp != ADDRESS_FAMILY_NO) {
-                        log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
-                                    network->filename);
-                        network->dhcp = ADDRESS_FAMILY_NO;
-                }
                 if (network->dhcp_server) {
                         log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
                                     network->filename);
                         network->dhcp_server = false;
                 }
-                if (network->n_static_addresses > 0) {
+                if (!ordered_hashmap_isempty(network->addresses_by_section))
                         log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
                                     network->filename);
-                        while ((address = network->static_addresses))
-                                address_free(address);
-                }
-                if (network->n_static_routes > 0) {
+                if (!hashmap_isempty(network->routes_by_section))
                         log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
                                     network->filename);
-                        while ((route = network->static_routes))
-                                route_free(route);
-                }
+
+                network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
+                network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
         }
 
         if (network->link_local < 0)
                 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
 
-        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
-                if (network->ipv6_accept_ra > 0) {
-                        log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
-                                    "Disabling IPv6AcceptRA=.", network->filename);
-                        network->ipv6_accept_ra = false;
-                }
-
-                if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
-                        log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
-                                    "Disabling DHCPv6 client.", network->filename);
-                        SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
-                }
-
-                if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
-                        log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
-                                    "Disabling IPv6PrefixDelegation=.", network->filename);
-                        network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
-                }
-        }
-
         if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
             !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
                 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
@@ -257,13 +221,14 @@ int network_verify(Network *network) {
                 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
         }
 
-        if (network->ipv6_accept_ra < 0 && network->bridge)
-                network->ipv6_accept_ra = false;
-
         /* IPMasquerade=yes implies IPForward=yes */
         if (network->ip_masquerade)
                 network->ip_forward |= ADDRESS_FAMILY_IPV4;
 
+        network_adjust_ipv6_accept_ra(network);
+        network_adjust_dhcp(network);
+        network_adjust_radv(network);
+
         if (network->mtu > 0 && network->dhcp_use_mtu) {
                 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
                             "Disabling UseMTU=.", network->filename);
@@ -290,54 +255,23 @@ int network_verify(Network *network) {
         if (network->keep_configuration < 0)
                 network->keep_configuration = KEEP_CONFIGURATION_NO;
 
-        LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
-                if (address_section_verify(address) < 0)
-                        address_free(address);
-
-        LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
-                if (route_section_verify(route, network) < 0)
-                        route_free(route);
-
-        LIST_FOREACH_SAFE(nexthops, nexthop, nextnop_next, network->static_nexthops)
-                if (nexthop_section_verify(nexthop) < 0)
-                        nexthop_free(nexthop);
-
-        LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
-                if (section_is_invalid(fdb->section))
-                        fdb_entry_free(fdb);
-
-        LIST_FOREACH_SAFE(static_mdb_entries, mdb, mdb_next, network->static_mdb_entries)
-                if (mdb_entry_verify(mdb) < 0)
-                        mdb_entry_free(mdb);
-
-        LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
-                if (neighbor_section_verify(neighbor) < 0)
-                        neighbor_free(neighbor);
-
-        LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
-                if (section_is_invalid(label->section))
-                        address_label_free(label);
-
-        LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
-                if (section_is_invalid(prefix->section))
-                        prefix_free(prefix);
-
-        LIST_FOREACH_SAFE(route_prefixes, route_prefix, route_prefix_next, network->static_route_prefixes)
-                if (section_is_invalid(route_prefix->section))
-                        route_prefix_free(route_prefix);
-
-        LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
-                if (routing_policy_rule_section_verify(rule) < 0)
-                        routing_policy_rule_free(rule);
-
-        bool has_root = false, has_clsact = false;
-        ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section)
-                if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
-                        traffic_control_free(tc);
+        if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
+                log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
+                network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
+        }
 
-        ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
-                if (sr_iov_section_verify(sr_iov) < 0)
-                        sr_iov_free(sr_iov);
+        network_drop_invalid_addresses(network);
+        network_drop_invalid_routes(network);
+        network_drop_invalid_nexthops(network);
+        network_drop_invalid_fdb_entries(network);
+        network_drop_invalid_mdb_entries(network);
+        network_drop_invalid_neighbors(network);
+        network_drop_invalid_address_labels(network);
+        network_drop_invalid_prefixes(network);
+        network_drop_invalid_route_prefixes(network);
+        network_drop_invalid_routing_policy_rules(network);
+        network_drop_invalid_traffic_control(network);
+        network_drop_invalid_sr_iov(network);
 
         return 0;
 }
@@ -395,7 +329,16 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
 
                 .required_for_online = true,
                 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
+                .arp = -1,
+                .multicast = -1,
+                .allmulticast = -1,
+
+                .configure_without_carrier = false,
+                .ignore_carrier_loss = -1,
+                .keep_configuration = _KEEP_CONFIGURATION_INVALID,
+
                 .dhcp = ADDRESS_FAMILY_NO,
+                .duid.type = _DUID_TYPE_INVALID,
                 .dhcp_critical = -1,
                 .dhcp_use_ntp = true,
                 .dhcp_use_sip = true,
@@ -417,14 +360,17 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .dhcp_use_mtu = false,
                 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
                 .dhcp_use_timezone = false,
-                .rapid_commit = true,
+                .dhcp_ip_service_type = -1,
 
+                .dhcp6_rapid_commit = true,
                 .dhcp6_route_metric = DHCP_ROUTE_METRIC,
                 .dhcp6_use_ntp = true,
                 .dhcp6_use_dns = true,
 
-                .dhcp6_pd_subnet_id = -1,
+                .dhcp6_pd = -1,
+                .dhcp6_pd_announce = true,
                 .dhcp6_pd_assign = true,
+                .dhcp6_pd_subnet_id = -1,
 
                 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
                 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
@@ -463,17 +409,13 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
 
                 .ipv4_accept_local = -1,
-
                 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
                 .ipv6_accept_ra = -1,
                 .ipv6_dad_transmits = -1,
                 .ipv6_hop_limit = -1,
                 .ipv6_proxy_ndp = -1,
-                .duid.type = _DUID_TYPE_INVALID,
                 .proxy_arp = -1,
-                .arp = -1,
-                .multicast = -1,
-                .allmulticast = -1,
+
                 .ipv6_accept_ra_use_dns = true,
                 .ipv6_accept_ra_use_autonomous_prefix = true,
                 .ipv6_accept_ra_use_onlink_prefix = true,
@@ -481,15 +423,11 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .ipv6_accept_ra_route_table_set = false,
                 .ipv6_accept_ra_start_dhcp6_client = true,
 
-                .configure_without_carrier = false,
-                .ignore_carrier_loss = -1,
-                .keep_configuration = _KEEP_CONFIGURATION_INVALID,
                 .can_triple_sampling = -1,
                 .can_termination = -1,
                 .can_listen_only = -1,
                 .can_fd_mode = -1,
                 .can_non_iso = -1,
-                .ip_service_type = -1,
         };
 
         r = config_parse_many(
@@ -515,6 +453,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         "BridgeFDB\0"
                         "BridgeMDB\0"
                         "BridgeVLAN\0"
+                        "IPv6SendRA\0"
                         "IPv6PrefixDelegation\0"
                         "IPv6Prefix\0"
                         "IPv6RoutePrefix\0"
@@ -644,18 +583,6 @@ failure:
 }
 
 static Network *network_free(Network *network) {
-        IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
-        RoutePrefix *route_prefix;
-        RoutingPolicyRule *rule;
-        AddressLabel *label;
-        FdbEntry *fdb_entry;
-        MdbEntry *mdb_entry;
-        Neighbor *neighbor;
-        Address *address;
-        NextHop *nexthop;
-        Prefix *prefix;
-        Route *route;
-
         if (!network)
                 return NULL;
 
@@ -687,18 +614,15 @@ static Network *network_free(Network *network) {
         strv_free(network->dhcp6_user_class);
         strv_free(network->dhcp6_vendor_class);
 
-        if (network->dhcp_acd)
-                sd_ipv4acd_unref(network->dhcp_acd);
-
         strv_free(network->ntp);
         for (unsigned i = 0; i < network->n_dns; i++)
                 in_addr_full_free(network->dns[i]);
         free(network->dns);
-        ordered_set_free_free(network->search_domains);
-        ordered_set_free_free(network->route_domains);
+        ordered_set_free(network->search_domains);
+        ordered_set_free(network->route_domains);
         strv_free(network->bind_carrier);
 
-        ordered_set_free_free(network->router_search_domains);
+        ordered_set_free(network->router_search_domains);
         free(network->router_dns);
         set_free_free(network->ndisc_deny_listed_prefix);
 
@@ -711,49 +635,17 @@ static Network *network_free(Network *network) {
         netdev_unref(network->vrf);
         hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
 
-        while ((route = network->static_routes))
-                route_free(route);
-
-        while ((nexthop = network->static_nexthops))
-                nexthop_free(nexthop);
-
-        while ((address = network->static_addresses))
-                address_free(address);
-
-        while ((fdb_entry = network->static_fdb_entries))
-                fdb_entry_free(fdb_entry);
-
-        while ((mdb_entry = network->static_mdb_entries))
-                mdb_entry_free(mdb_entry);
-
-        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);
-
-        while ((prefix = network->static_prefixes))
-                prefix_free(prefix);
-
-        while ((route_prefix = network->static_route_prefixes))
-                route_prefix_free(route_prefix);
-
-        while ((rule = network->rules))
-                routing_policy_rule_free(rule);
-
-        hashmap_free(network->addresses_by_section);
-        hashmap_free(network->routes_by_section);
-        hashmap_free(network->nexthops_by_section);
-        hashmap_free(network->fdb_entries_by_section);
-        hashmap_free(network->mdb_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->route_prefixes_by_section);
-        hashmap_free(network->rules_by_section);
+        set_free_free(network->ipv6_proxy_ndp_addresses);
+        ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
+        hashmap_free_with_destructor(network->routes_by_section, route_free);
+        hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
+        hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free);
+        hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
+        hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
+        hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
+        hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
+        hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
+        hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
         ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
         ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
 
@@ -866,30 +758,33 @@ bool network_has_static_ipv6_configurations(Network *network) {
 
         assert(network);
 
-        LIST_FOREACH(addresses, address, network->static_addresses)
+        ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
                 if (address->family == AF_INET6)
                         return true;
 
-        LIST_FOREACH(routes, route, network->static_routes)
+        HASHMAP_FOREACH(route, network->routes_by_section)
                 if (route->family == AF_INET6)
                         return true;
 
-        LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
+        HASHMAP_FOREACH(fdb, network->fdb_entries_by_section)
                 if (fdb->family == AF_INET6)
                         return true;
 
-        LIST_FOREACH(static_mdb_entries, mdb, network->static_mdb_entries)
+        HASHMAP_FOREACH(mdb, network->mdb_entries_by_section)
                 if (mdb->family == AF_INET6)
                         return true;
 
-        LIST_FOREACH(neighbors, neighbor, network->neighbors)
+        HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
                 if (neighbor->family == AF_INET6)
                         return true;
 
-        if (!LIST_IS_EMPTY(network->address_labels))
+        if (!hashmap_isempty(network->address_labels_by_section))
+                return true;
+
+        if (!hashmap_isempty(network->prefixes_by_section))
                 return true;
 
-        if (!LIST_IS_EMPTY(network->static_prefixes))
+        if (!hashmap_isempty(network->route_prefixes_by_section))
                 return true;
 
         return false;
@@ -967,8 +862,8 @@ int config_parse_domains(
         assert(rvalue);
 
         if (isempty(rvalue)) {
-                n->search_domains = ordered_set_free_free(n->search_domains);
-                n->route_domains = ordered_set_free_free(n->route_domains);
+                n->search_domains = ordered_set_free(n->search_domains);
+                n->route_domains = ordered_set_free(n->route_domains);
                 return 0;
         }
 
@@ -1016,7 +911,7 @@ int config_parse_domains(
                 }
 
                 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
-                r = ordered_set_ensure_allocated(set, &string_hash_ops);
+                r = ordered_set_ensure_allocated(set, &string_hash_ops_free);
                 if (r < 0)
                         return log_oom();
 
@@ -1026,95 +921,6 @@ int config_parse_domains(
         }
 }
 
-int config_parse_ipv6token(
-                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) {
-
-        union in_addr_union buffer;
-        struct in6_addr *token = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(token);
-
-        r = in_addr_from_string(AF_INET6, rvalue, &buffer);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse IPv6 token, ignoring: %s", rvalue);
-                return 0;
-        }
-
-        if (in_addr_is_null(AF_INET6, &buffer)) {
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
-                return 0;
-        }
-
-        if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
-                return 0;
-        }
-
-        *token = buffer.in6;
-
-        return 0;
-}
-
-static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
-        [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
-        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
-        [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
-                                        IPV6_PRIVACY_EXTENSIONS_YES);
-
-int config_parse_ipv6_privacy_extensions(
-                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) {
-
-        IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(ipv6_privacy_extensions);
-
-        s = ipv6_privacy_extensions_from_string(rvalue);
-        if (s < 0) {
-                if (streq(rvalue, "kernel"))
-                        s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
-                else {
-                        log_syntax(unit, LOG_WARNING, filename, line, 0,
-                                   "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
-                        return 0;
-                }
-        }
-
-        *ipv6_privacy_extensions = s;
-
-        return 0;
-}
-
 int config_parse_hostname(
                 const char *unit,
                 const char *filename,
index 5ba0bc705d2f326437ddb1294ad97929846cd16f..92c7a4636fed62371c0632b5612be32152b67312 100644 (file)
@@ -5,45 +5,27 @@
 
 #include "sd-bus.h"
 #include "sd-device.h"
-#include "sd-ipv4acd.h"
 
 #include "bridge.h"
 #include "condition.h"
 #include "conf-parser.h"
 #include "hashmap.h"
 #include "netdev.h"
-#include "networkd-address-label.h"
-#include "networkd-address.h"
 #include "networkd-brvlan.h"
 #include "networkd-dhcp-common.h"
 #include "networkd-dhcp4.h"
 #include "networkd-dhcp6.h"
 #include "networkd-dhcp-server.h"
-#include "networkd-fdb.h"
-#include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-lldp-rx.h"
 #include "networkd-lldp-tx.h"
-#include "networkd-mdb.h"
 #include "networkd-ndisc.h"
-#include "networkd-neighbor.h"
-#include "networkd-nexthop.h"
 #include "networkd-radv.h"
-#include "networkd-route.h"
-#include "networkd-routing-policy-rule.h"
+#include "networkd-sysctl.h"
 #include "networkd-util.h"
 #include "ordered-set.h"
 #include "resolve-util.h"
 #include "socket-netlink.h"
 
-typedef enum IPv6PrivacyExtensions {
-        /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
-        IPV6_PRIVACY_EXTENSIONS_NO,
-        IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC,
-        IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */
-        _IPV6_PRIVACY_EXTENSIONS_MAX,
-        _IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
-} IPv6PrivacyExtensions;
-
 typedef enum KeepConfiguration {
         KEEP_CONFIGURATION_NO            = 0,
         KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0,
@@ -75,12 +57,14 @@ typedef struct NetworkDHCPServerEmitAddress {
 struct Network {
         Manager *manager;
 
-        char *filename;
+        unsigned n_ref;
+
         char *name;
+        char *filename;
         usec_t timestamp;
+        char *description;
 
-        unsigned n_ref;
-
+        /* [Match] section */
         Set *match_mac;
         Set *match_permanent_mac;
         char **match_path;
@@ -93,8 +77,7 @@ struct Network {
         Set *match_bssid;
         LIST_HEAD(Condition, conditions);
 
-        char *description;
-
+        /* Master or stacked netdevs */
         NetDev *bridge;
         NetDev *bond;
         NetDev *vrf;
@@ -105,9 +88,31 @@ struct Network {
         char *vrf_name;
         Hashmap *stacked_netdev_names;
 
+        /* [Link] section */
+        struct ether_addr *mac;
+        uint32_t mtu;
+        uint32_t group;
+        int arp;
+        int multicast;
+        int allmulticast;
+        bool unmanaged;
+        bool required_for_online; /* Is this network required to be considered online? */
+        LinkOperationalStateRange required_operstate_for_online;
+
+        /* misc settings */
+        bool configure_without_carrier;
+        int ignore_carrier_loss;
+        KeepConfiguration keep_configuration;
+        char **bind_carrier;
+        bool default_route_on_device;
+        bool ip_masquerade;
+
         /* DHCP Client Support */
         AddressFamily dhcp;
         DHCPClientIdentifier dhcp_client_identifier;
+        DUID duid;
+        uint32_t iaid;
+        bool iaid_set;
         char *dhcp_vendor_class_identifier;
         char *dhcp_mudurl;
         char **dhcp_user_class;
@@ -120,7 +125,7 @@ struct Network {
         uint32_t dhcp_route_mtu;
         uint16_t dhcp_client_port;
         int dhcp_critical;
-        int ip_service_type;
+        int dhcp_ip_service_type;
         bool dhcp_anonymize;
         bool dhcp_send_hostname;
         bool dhcp_broadcast;
@@ -134,26 +139,23 @@ struct Network {
         bool dhcp_use_routes;
         int dhcp_use_gateway;
         bool dhcp_use_timezone;
-        bool rapid_commit;
         bool dhcp_use_hostname;
         bool dhcp_route_table_set;
         bool dhcp_send_release;
         bool dhcp_send_decline;
         DHCPUseDomains dhcp_use_domains;
-        sd_ipv4acd *dhcp_acd;
         Set *dhcp_deny_listed_ip;
         Set *dhcp_allow_listed_ip;
         Set *dhcp_request_options;
         OrderedHashmap *dhcp_client_send_options;
         OrderedHashmap *dhcp_client_send_vendor_options;
-        OrderedHashmap *dhcp_server_send_options;
-        OrderedHashmap *dhcp_server_send_vendor_options;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
         bool dhcp6_use_dns_set;
         bool dhcp6_use_ntp;
         bool dhcp6_use_ntp_set;
+        bool dhcp6_rapid_commit;
         uint8_t dhcp6_pd_length;
         uint32_t dhcp6_route_metric;
         bool dhcp6_route_metric_set;
@@ -165,6 +167,8 @@ struct Network {
         OrderedHashmap *dhcp6_client_send_options;
         OrderedHashmap *dhcp6_client_send_vendor_options;
         Set *dhcp6_request_options;
+        /* Start DHCPv6 PD also when 'O' RA flag is set, see RFC 7084, WPD-4 */
+        bool dhcp6_force_pd_other_information;
 
         /* DHCP Server Support */
         bool dhcp_server;
@@ -175,15 +179,15 @@ struct Network {
         usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec;
         uint32_t dhcp_server_pool_offset;
         uint32_t dhcp_server_pool_size;
+        OrderedHashmap *dhcp_server_send_options;
+        OrderedHashmap *dhcp_server_send_vendor_options;
 
         /* link local addressing support */
         AddressFamily link_local;
         IPv6LinkLocalAddressGenMode ipv6ll_address_gen_mode;
         bool ipv4ll_route;
 
-        bool default_route_on_device;
-
-        /* IPv6 prefix delegation support */
+        /* IPv6 RA support */
         RADVPrefixDelegation router_prefix_delegation;
         usec_t router_lifetime_usec;
         uint8_t router_preference;
@@ -195,13 +199,12 @@ struct Network {
         struct in6_addr *router_dns;
         unsigned n_router_dns;
         OrderedSet *router_search_domains;
-        bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
-                                                  RA flag is set, see RFC 7084,
-                                                  WPD-4 */
 
         /* DHCPv6 Prefix Delegation support */
-        int64_t dhcp6_pd_subnet_id;
+        int dhcp6_pd;
+        bool dhcp6_pd_announce;
         bool dhcp6_pd_assign;
+        int64_t dhcp6_pd_subnet_id;
         union in_addr_union dhcp6_pd_token;
 
         /* Bridge Support */
@@ -220,6 +223,7 @@ struct Network {
         uint16_t priority;
         MulticastRouter multicast_router;
 
+        /* Bridge VLAN */
         bool use_br_vlan;
         uint16_t pvid;
         uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN];
@@ -237,17 +241,19 @@ struct Network {
         int can_fd_mode;
         int can_non_iso;
 
+        /* sysctl settings */
         AddressFamily ip_forward;
-        bool ip_masquerade;
         int ipv4_accept_local;
-
-        int ipv6_accept_ra;
         int ipv6_dad_transmits;
         int ipv6_hop_limit;
-        int ipv6_proxy_ndp;
         int proxy_arp;
         uint32_t ipv6_mtu;
+        IPv6PrivacyExtensions ipv6_privacy_extensions;
+        int ipv6_proxy_ndp;
+        Set *ipv6_proxy_ndp_addresses;
 
+        /* IPv6 accept RA */
+        int ipv6_accept_ra;
         bool ipv6_accept_ra_use_dns;
         bool ipv6_accept_ra_use_autonomous_prefix;
         bool ipv6_accept_ra_use_onlink_prefix;
@@ -260,56 +266,12 @@ struct Network {
         Set *ndisc_deny_listed_prefix;
         OrderedSet *ipv6_tokens;
 
-        IPv6PrivacyExtensions ipv6_privacy_extensions;
-
-        struct ether_addr *mac;
-        uint32_t mtu;
-        uint32_t group;
-        int arp;
-        int multicast;
-        int allmulticast;
-        bool unmanaged;
-        bool configure_without_carrier;
-        int ignore_carrier_loss;
-        KeepConfiguration keep_configuration;
-        uint32_t iaid;
-        DUID duid;
-
-        bool iaid_set;
-
-        bool required_for_online; /* Is this network required to be considered online? */
-        LinkOperationalStateRange required_operstate_for_online;
-
         /* LLDP support */
         LLDPMode lldp_mode; /* LLDP reception */
         LLDPEmit lldp_emit; /* LLDP transmission */
         char *lldp_mud;    /* LLDP MUD URL */
 
-        LIST_HEAD(Address, static_addresses);
-        LIST_HEAD(Route, static_routes);
-        LIST_HEAD(NextHop, static_nexthops);
-        LIST_HEAD(FdbEntry, static_fdb_entries);
-        LIST_HEAD(MdbEntry, static_mdb_entries);
-        LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
-        LIST_HEAD(Neighbor, neighbors);
-        LIST_HEAD(AddressLabel, address_labels);
-        LIST_HEAD(Prefix, static_prefixes);
-        LIST_HEAD(RoutePrefix, static_route_prefixes);
-        LIST_HEAD(RoutingPolicyRule, rules);
-
-        unsigned n_static_addresses;
-        unsigned n_static_routes;
-        unsigned n_static_nexthops;
-        unsigned n_static_fdb_entries;
-        unsigned n_static_mdb_entries;
-        unsigned n_ipv6_proxy_ndp_addresses;
-        unsigned n_neighbors;
-        unsigned n_address_labels;
-        unsigned n_static_prefixes;
-        unsigned n_static_route_prefixes;
-        unsigned n_rules;
-
-        Hashmap *addresses_by_section;
+        OrderedHashmap *addresses_by_section;
         Hashmap *routes_by_section;
         Hashmap *nexthops_by_section;
         Hashmap *fdb_entries_by_section;
@@ -326,7 +288,6 @@ struct Network {
         struct in_addr_full **dns;
         unsigned n_dns;
         OrderedSet *search_domains, *route_domains;
-
         int dns_default_route;
         ResolveSupport llmnr;
         ResolveSupport mdns;
@@ -334,8 +295,8 @@ struct Network {
         DnsOverTlsMode dns_over_tls_mode;
         Set *dnssec_negative_trust_anchors;
 
+        /* NTP */
         char **ntp;
-        char **bind_carrier;
 };
 
 Network *network_ref(Network *network);
@@ -360,8 +321,6 @@ bool network_has_static_ipv6_configurations(Network *network);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev);
 CONFIG_PARSER_PROTOTYPE(config_parse_tunnel);
-CONFIG_PARSER_PROTOTYPE(config_parse_ipv6token);
-CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);
 CONFIG_PARSER_PROTOTYPE(config_parse_domains);
 CONFIG_PARSER_PROTOTYPE(config_parse_dns);
 CONFIG_PARSER_PROTOTYPE(config_parse_hostname);
@@ -374,9 +333,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
 
 const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
 
-const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
-IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
-
 const char* keep_configuration_to_string(KeepConfiguration i) _const_;
 KeepConfiguration keep_configuration_from_string(const char *s) _pure_;
 
index 6d89be1a25d55a48f48d682959289b9a9c26967d..6edeaabf88afa0f2e76f92bbc6dea938432d7d8f 100644 (file)
@@ -5,17 +5,37 @@
 #include <linux/nexthop.h>
 
 #include "alloc-util.h"
-#include "conf-parser.h"
-#include "in-addr-util.h"
 #include "netlink-util.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
+#include "networkd-network.h"
 #include "networkd-nexthop.h"
 #include "parse-util.h"
 #include "set.h"
 #include "string-util.h"
-#include "util.h"
 
-int nexthop_new(NextHop **ret) {
+NextHop *nexthop_free(NextHop *nexthop) {
+        if (!nexthop)
+                return NULL;
+
+        if (nexthop->network) {
+                assert(nexthop->section);
+                hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section);
+        }
+
+        network_config_section_free(nexthop->section);
+
+        if (nexthop->link) {
+                set_remove(nexthop->link->nexthops, nexthop);
+                set_remove(nexthop->link->nexthops_foreign, nexthop);
+        }
+
+        return mfree(nexthop);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free);
+
+static int nexthop_new(NextHop **ret) {
         _cleanup_(nexthop_freep) NextHop *nexthop = NULL;
 
         nexthop = new(NextHop, 1);
@@ -38,19 +58,17 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
 
         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;
+        assert(filename);
+        assert(section_line > 0);
 
-                nexthop = hashmap_get(network->nexthops_by_section, n);
-                if (nexthop) {
-                        *ret = TAKE_PTR(nexthop);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        nexthop = hashmap_get(network->nexthops_by_section, n);
+        if (nexthop) {
+                *ret = TAKE_PTR(nexthop);
+                return 0;
         }
 
         r = nexthop_new(&nexthop);
@@ -59,55 +77,24 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
 
         nexthop->protocol = RTPROT_STATIC;
         nexthop->network = network;
-        LIST_PREPEND(nexthops, network->static_nexthops, nexthop);
-        network->n_static_nexthops++;
+        nexthop->section = TAKE_PTR(n);
 
-        if (filename) {
-                nexthop->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(nexthop);
-
         return 0;
 }
 
-void nexthop_free(NextHop *nexthop) {
-        if (!nexthop)
-                return;
-
-        if (nexthop->network) {
-                LIST_REMOVE(nexthops, nexthop->network->static_nexthops, nexthop);
-
-                assert(nexthop->network->n_static_nexthops > 0);
-                nexthop->network->n_static_nexthops--;
-
-                if (nexthop->section)
-                        hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section);
-        }
-
-        network_config_section_free(nexthop->section);
-
-        if (nexthop->link) {
-                set_remove(nexthop->link->nexthops, nexthop);
-                set_remove(nexthop->link->nexthops_foreign, nexthop);
-        }
-
-        free(nexthop);
-}
-
 static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
         assert(nexthop);
 
         siphash24_compress(&nexthop->id, sizeof(nexthop->id), state);
-        siphash24_compress(&nexthop->oif, sizeof(nexthop->oif), state);
         siphash24_compress(&nexthop->family, sizeof(nexthop->family), state);
 
         switch (nexthop->family) {
@@ -129,27 +116,14 @@ static int nexthop_compare_func(const NextHop *a, const NextHop *b) {
         if (r != 0)
                 return r;
 
-        r = CMP(a->oif, b->oif);
-        if (r != 0)
-                return r;
-
         r = CMP(a->family, b->family);
         if (r != 0)
                 return r;
 
-        switch (a->family) {
-        case AF_INET:
-        case AF_INET6:
-
-                r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
-                if (r != 0)
-                        return r;
+        if (IN_SET(a->family, AF_INET, AF_INET6))
+                return memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
 
-                return 0;
-        default:
-                /* treat any other address family as AF_UNSPEC */
-                return 0;
-        }
+        return 0;
 }
 
 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@@ -159,17 +133,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 nexthop_compare_func,
                 nexthop_free);
 
-bool nexthop_equal(NextHop *r1, NextHop *r2) {
-        if (r1 == r2)
-                return true;
-
-        if (!r1 || !r2)
-                return false;
-
-        return nexthop_compare_func(r1, r2) == 0;
-}
-
-int nexthop_get(Link *link, NextHop *in, NextHop **ret) {
+static int nexthop_get(Link *link, NextHop *in, NextHop **ret) {
         NextHop *existing;
 
         assert(link);
@@ -205,7 +169,6 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
                 return r;
 
         nexthop->id = in->id;
-        nexthop->oif = in->oif;
         nexthop->family = in->family;
         nexthop->gw = in->gw;
 
@@ -225,11 +188,11 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
         return 0;
 }
 
-int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) {
+static int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) {
         return nexthop_add_internal(link, &link->nexthops_foreign, in, ret);
 }
 
-int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
+static int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
         NextHop *nexthop;
         int r;
 
@@ -258,71 +221,34 @@ int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
         return 0;
 }
 
-static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
-        assert(m);
         assert(link);
-        assert(link->ifname);
+        assert(link->nexthop_messages > 0);
+
+        link->nexthop_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 != -ESRCH)
-                log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring");
-
-        return 1;
-}
-
-int nexthop_remove(NextHop *nexthop, Link *link,
-                   link_netlink_message_handler_t callback) {
-
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        int r;
-
-        assert(link);
-        assert(link->manager);
-        assert(link->manager->rtnl);
-        assert(link->ifindex > 0);
-        assert(IN_SET(nexthop->family, AF_INET, AF_INET6));
-
-        r = sd_rtnl_message_new_nexthop(link->manager->rtnl, &req,
-                                      RTM_DELNEXTHOP, nexthop->family,
-                                      nexthop->protocol);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not create RTM_DELNEXTHOP message: %m");
-
-        if (DEBUG_LOGGING) {
-                _cleanup_free_ char *gw = NULL;
-
-                if (!in_addr_is_null(nexthop->family, &nexthop->gw))
-                        (void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
-
-                log_link_debug(link, "Removing nexthop: gw: %s", strna(gw));
+        if (r < 0 && r != -EEXIST) {
+                log_link_message_warning_errno(link, m, r, "Could not set nexthop");
+                link_enter_failed(link);
+                return 1;
         }
 
-        if (in_addr_is_null(nexthop->family, &nexthop->gw) == 0) {
-                r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, nexthop->family, &nexthop->gw);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
+        if (link->nexthop_messages == 0) {
+                log_link_debug(link, "Nexthop set");
+                link->static_nexthops_configured = true;
+                link_check_ready(link);
         }
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req,
-                               callback ?: nexthop_remove_handler,
-                               link_netlink_destroy_callback, link);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
-        link_ref(link);
-
-        return 0;
+        return 1;
 }
 
-int nexthop_configure(
-                NextHop *nexthop,
-                Link *link,
-                link_netlink_message_handler_t callback) {
+static int nexthop_configure(NextHop *nexthop, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -331,7 +257,6 @@ int nexthop_configure(
         assert(link->manager->rtnl);
         assert(link->ifindex > 0);
         assert(IN_SET(nexthop->family, AF_INET, AF_INET6));
-        assert(callback);
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *gw = NULL;
@@ -366,7 +291,7 @@ int nexthop_configure(
                         return log_link_error_errno(link, r, "Could not set nexthop family: %m");
         }
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
+        r = netlink_call_async(link->manager->rtnl, NULL, req, nexthop_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -380,7 +305,141 @@ int nexthop_configure(
         return 1;
 }
 
-int nexthop_section_verify(NextHop *nh) {
+int link_set_nexthop(Link *link) {
+        NextHop *nh;
+        int r;
+
+        assert(link);
+        assert(link->network);
+
+        link->static_nexthops_configured = false;
+
+        HASHMAP_FOREACH(nh, link->network->nexthops_by_section) {
+                r = nexthop_configure(nh, link);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not set nexthop: %m");
+
+                link->nexthop_messages++;
+        }
+
+        if (link->nexthop_messages == 0) {
+                link->static_nexthops_configured = true;
+                link_check_ready(link);
+        } else {
+                log_link_debug(link, "Setting nexthop");
+                link_set_state(link, LINK_STATE_CONFIGURING);
+        }
+
+        return 1;
+}
+
+int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
+        _cleanup_(nexthop_freep) NextHop *tmp = NULL;
+        _cleanup_free_ char *gateway = NULL;
+        NextHop *nexthop = NULL;
+        uint32_t ifindex;
+        uint16_t type;
+        Link *link;
+        int r;
+
+        assert(rtnl);
+        assert(message);
+        assert(m);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
+
+                return 0;
+        }
+
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(type, RTM_NEWNEXTHOP, RTM_DELNEXTHOP)) {
+                log_warning("rtnl: received unexpected message type %u when processing nexthop, ignoring.", type);
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, NHA_OIF, &ifindex);
+        if (r == -ENODATA) {
+                log_warning_errno(r, "rtnl: received nexthop message without NHA_OIF attribute, ignoring: %m");
+                return 0;
+        } else if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
+                return 0;
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received nexthop message with invalid ifindex %"PRIu32", ignoring.", ifindex);
+                return 0;
+        }
+
+        r = link_get(m, ifindex, &link);
+        if (r < 0 || !link) {
+                if (!m->enumerating)
+                        log_warning("rtnl: received nexthop message for link (%"PRIu32") we do not know about, ignoring", ifindex);
+                return 0;
+        }
+
+        r = nexthop_new(&tmp);
+        if (r < 0)
+                return log_oom();
+
+        r = sd_rtnl_message_get_family(message, &tmp->family);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: could not get nexthop family, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6))
+                return log_link_debug(link, "rtnl: received nexthop message with invalid family %d, ignoring.", tmp->family);
+
+        r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, tmp->family, &tmp->gw);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, NHA_ID, &tmp->id);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: could not get NHA_ID attribute, ignoring: %m");
+                return 0;
+        }
+
+        (void) nexthop_get(link, tmp, &nexthop);
+
+        if (DEBUG_LOGGING)
+                (void) in_addr_to_string(tmp->family, &tmp->gw, &gateway);
+
+        switch (type) {
+        case RTM_NEWNEXTHOP:
+                if (nexthop)
+                        log_link_debug(link, "Received remembered nexthop: %s, id: %d", strna(gateway), tmp->id);
+                else {
+                        log_link_debug(link, "Remembering foreign nexthop: %s, id: %d", strna(gateway), tmp->id);
+                        r = nexthop_add_foreign(link, tmp, &nexthop);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m");
+                                return 0;
+                        }
+                }
+                break;
+        case RTM_DELNEXTHOP:
+                if (nexthop) {
+                        log_link_debug(link, "Forgetting nexthop: %s, id: %d", strna(gateway), tmp->id);
+                        nexthop_free(nexthop);
+                } else
+                        log_link_debug(link, "Kernel removed a nexthop we don't remember: %s, id: %d, ignoring.",
+                                       strna(gateway), tmp->id);
+                break;
+
+        default:
+                assert_not_reached("Received invalid RTNL message type");
+        }
+
+        return 1;
+}
+
+static int nexthop_section_verify(NextHop *nh) {
         if (section_is_invalid(nh->section))
                 return -EINVAL;
 
@@ -390,6 +449,16 @@ int nexthop_section_verify(NextHop *nh) {
         return 0;
 }
 
+void network_drop_invalid_nexthops(Network *network) {
+        NextHop *nh;
+
+        assert(network);
+
+        HASHMAP_FOREACH(nh, network->nexthops_by_section)
+                if (nexthop_section_verify(nh) < 0)
+                        nexthop_free(nh);
+}
+
 int config_parse_nexthop_id(
                 const char *unit,
                 const char *filename,
index 28cbdad738e770e42c56b31914932a3407f325f9..3cdb068efd73f9605785b86f4ee785db15de92e1 100644 (file)
@@ -4,16 +4,19 @@
 
 #pragma once
 
-#include "conf-parser.h"
-#include "macro.h"
+#include <inttypes.h>
 
-typedef struct NextHop NextHop;
-typedef struct NetworkConfigSection NetworkConfigSection;
+#include "sd-netlink.h"
 
-#include "networkd-network.h"
+#include "conf-parser.h"
+#include "in-addr-util.h"
 #include "networkd-util.h"
 
-struct NextHop {
+typedef struct Link Link;
+typedef struct Manager Manager;
+typedef struct Network Network;
+
+typedef struct NextHop {
         Network *network;
         NetworkConfigSection *section;
 
@@ -21,30 +24,18 @@ struct NextHop {
 
         unsigned char protocol;
 
-        int family;
-        uint32_t oif;
         uint32_t id;
-
+        int family;
         union in_addr_union gw;
+} NextHop;
 
-        LIST_FIELDS(NextHop, nexthops);
-};
-
-extern const struct hash_ops nexthop_hash_ops;
-
-int nexthop_new(NextHop **ret);
-void nexthop_free(NextHop *nexthop);
-int nexthop_configure(NextHop *nexthop, Link *link, link_netlink_message_handler_t callback);
-int nexthop_remove(NextHop *nexthop, Link *link, link_netlink_message_handler_t callback);
+NextHop *nexthop_free(NextHop *nexthop);
 
-int nexthop_get(Link *link, NextHop *in, NextHop **ret);
-int nexthop_add(Link *link, NextHop *in, NextHop **ret);
-int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret);
-bool nexthop_equal(NextHop *r1, NextHop *r2);
+void network_drop_invalid_nexthops(Network *network);
 
-int nexthop_section_verify(NextHop *nexthop);
+int link_set_nexthop(Link *link);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free);
+int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
 CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);
index 003a50b68b06ff2c727c0772d73b754a22a6e9ee..eb10f21cbd456602720043e8a934f8610e91dfdc 100644 (file)
@@ -7,35 +7,32 @@
 #include <arpa/inet.h>
 
 #include "dns-domain.h"
-#include "networkd-address.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
+#include "networkd-network.h"
 #include "networkd-radv.h"
 #include "parse-util.h"
-#include "sd-radv.h"
 #include "string-util.h"
 #include "string-table.h"
 #include "strv.h"
 
-void prefix_free(Prefix *prefix) {
+Prefix *prefix_free(Prefix *prefix) {
         if (!prefix)
-                return;
+                return NULL;
 
         if (prefix->network) {
-                LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
-                assert(prefix->network->n_static_prefixes > 0);
-                prefix->network->n_static_prefixes--;
-
-                if (prefix->section)
-                        hashmap_remove(prefix->network->prefixes_by_section,
-                                       prefix->section);
+                assert(prefix->section);
+                hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
         }
 
         network_config_section_free(prefix->section);
         sd_radv_prefix_unref(prefix->radv_prefix);
 
-        free(prefix);
+        return mfree(prefix);
 }
 
+DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
+
 static int prefix_new(Prefix **ret) {
         _cleanup_(prefix_freep) Prefix *prefix = NULL;
 
@@ -51,29 +48,24 @@ static int prefix_new(Prefix **ret) {
         return 0;
 }
 
-static int prefix_new_static(Network *network, const char *filename,
-                             unsigned section_line, Prefix **ret) {
+static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(prefix_freep) Prefix *prefix = 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;
+        assert(filename);
+        assert(section_line > 0);
 
-                if (section_line) {
-                        prefix = hashmap_get(network->prefixes_by_section, n);
-                        if (prefix) {
-                                *ret = TAKE_PTR(prefix);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                                return 0;
-                        }
-                }
+        prefix = hashmap_get(network->prefixes_by_section, n);
+        if (prefix) {
+                *ret = TAKE_PTR(prefix);
+                return 0;
         }
 
         r = prefix_new(&prefix);
@@ -81,26 +73,38 @@ static int prefix_new_static(Network *network, const char *filename,
                 return r;
 
         prefix->network = network;
-        LIST_APPEND(prefixes, network->static_prefixes, prefix);
-        network->n_static_prefixes++;
-
-        if (filename) {
-                prefix->section = TAKE_PTR(n);
+        prefix->section = TAKE_PTR(n);
 
-                r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(prefix);
 
         return 0;
 }
 
+RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
+        if (!prefix)
+                return NULL;
+
+        if (prefix->network) {
+                assert(prefix->section);
+                hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
+        }
+
+        network_config_section_free(prefix->section);
+        sd_radv_route_prefix_unref(prefix->radv_route_prefix);
+
+        return mfree(prefix);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
+
 static int route_prefix_new(RoutePrefix **ret) {
         _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
 
@@ -116,49 +120,24 @@ static int route_prefix_new(RoutePrefix **ret) {
         return 0;
 }
 
-void route_prefix_free(RoutePrefix *prefix) {
-        if (!prefix)
-                return;
-
-        if (prefix->network) {
-                LIST_REMOVE(route_prefixes, prefix->network->static_route_prefixes, prefix);
-                assert(prefix->network->n_static_route_prefixes > 0);
-                prefix->network->n_static_route_prefixes--;
-
-                if (prefix->section)
-                        hashmap_remove(prefix->network->route_prefixes_by_section,
-                                       prefix->section);
-        }
-
-        network_config_section_free(prefix->section);
-        sd_radv_route_prefix_unref(prefix->radv_route_prefix);
-
-        free(prefix);
-}
-
-static int route_prefix_new_static(Network *network, const char *filename,
-                                   unsigned section_line, RoutePrefix **ret) {
+static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(route_prefix_freep) RoutePrefix *prefix = 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;
+        assert(filename);
+        assert(section_line > 0);
 
-                if (section_line) {
-                        prefix = hashmap_get(network->route_prefixes_by_section, n);
-                        if (prefix) {
-                                *ret = TAKE_PTR(prefix);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                                return 0;
-                        }
-                }
+        prefix = hashmap_get(network->route_prefixes_by_section, n);
+        if (prefix) {
+                *ret = TAKE_PTR(prefix);
+                return 0;
         }
 
         r = route_prefix_new(&prefix);
@@ -166,36 +145,81 @@ static int route_prefix_new_static(Network *network, const char *filename,
                 return r;
 
         prefix->network = network;
-        LIST_APPEND(route_prefixes, network->static_route_prefixes, prefix);
-        network->n_static_route_prefixes++;
-
-        if (filename) {
-                prefix->section = TAKE_PTR(n);
+        prefix->section = TAKE_PTR(n);
 
-                r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(prefix);
 
         return 0;
 }
 
-int config_parse_prefix(const char *unit,
-                        const char *filename,
-                        unsigned line,
-                        const char *section,
-                        unsigned section_line,
-                        const char *lvalue,
-                        int ltype,
-                        const char *rvalue,
-                        void *data,
-                        void *userdata) {
+void network_drop_invalid_prefixes(Network *network) {
+        Prefix *prefix;
+
+        assert(network);
+
+        HASHMAP_FOREACH(prefix, network->prefixes_by_section)
+                if (section_is_invalid(prefix->section))
+                        prefix_free(prefix);
+}
+
+void network_drop_invalid_route_prefixes(Network *network) {
+        RoutePrefix *prefix;
+
+        assert(network);
+
+        HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
+                if (section_is_invalid(prefix->section))
+                        route_prefix_free(prefix);
+}
+
+void network_adjust_radv(Network *network) {
+        assert(network);
+
+        /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
+
+        if (network->dhcp6_pd < 0)
+                /* For backward compatibility. */
+                network->dhcp6_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
+
+        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
+                if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
+                        log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
+                                    "Disabling IPv6PrefixDelegation=.", network->filename);
+
+                network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
+        }
+
+        if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
+                network->n_router_dns = 0;
+                network->router_dns = mfree(network->router_dns);
+                network->router_search_domains = ordered_set_free(network->router_search_domains);
+        }
+
+        if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
+                network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
+                network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
+        }
+}
+
+int config_parse_prefix(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
         Network *network = userdata;
         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
@@ -230,16 +254,18 @@ int config_parse_prefix(const char *unit,
         return 0;
 }
 
-int config_parse_prefix_flags(const char *unit,
-                              const char *filename,
-                              unsigned line,
-                              const char *section,
-                              unsigned section_line,
-                              const char *lvalue,
-                              int ltype,
-                              const char *rvalue,
-                              void *data,
-                              void *userdata) {
+int config_parse_prefix_flags(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
         int r;
@@ -274,16 +300,18 @@ int config_parse_prefix_flags(const char *unit,
         return 0;
 }
 
-int config_parse_prefix_lifetime(const char *unit,
-                                 const char *filename,
-                                 unsigned line,
-                                 const char *section,
-                                 unsigned section_line,
-                                 const char *lvalue,
-                                 int ltype,
-                                 const char *rvalue,
-                                 void *data,
-                                 void *userdata) {
+int config_parse_prefix_lifetime(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
         usec_t usec;
@@ -362,16 +390,17 @@ int config_parse_prefix_assign(
         return 0;
 }
 
-int config_parse_route_prefix(const char *unit,
-                              const char *filename,
-                              unsigned line,
-                              const char *section,
-                              unsigned section_line,
-                              const char *lvalue,
-                              int ltype,
-                              const char *rvalue,
-                              void *data,
-                              void *userdata) {
+int config_parse_route_prefix(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
         Network *network = userdata;
         _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
@@ -406,16 +435,18 @@ int config_parse_route_prefix(const char *unit,
         return 0;
 }
 
-int config_parse_route_prefix_lifetime(const char *unit,
-                                       const char *filename,
-                                       unsigned line,
-                                       const char *section,
-                                       unsigned section_line,
-                                       const char *lvalue,
-                                       int ltype,
-                                       const char *rvalue,
-                                       void *data,
-                                       void *userdata) {
+int config_parse_route_prefix_lifetime(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
         _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
         usec_t usec;
@@ -451,16 +482,15 @@ int config_parse_route_prefix_lifetime(const char *unit,
         return 0;
 }
 
-static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
-                           size_t *n_dns) {
+static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
         _cleanup_free_ struct in6_addr *addresses = NULL;
-        size_t i, n_addresses = 0, n_allocated = 0;
+        size_t n_addresses = 0, n_allocated = 0;
 
         assert(network);
-        assert(dns);
-        assert(n_dns);
+        assert(ret_addresses);
+        assert(ret_size);
 
-        for (i = 0; i < network->n_dns; i++) {
+        for (size_t i = 0; i < network->n_dns; i++) {
                 union in_addr_union *addr;
 
                 if (network->dns[i]->family != AF_INET6)
@@ -479,11 +509,8 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
                 addresses[n_addresses++] = addr->in6;
         }
 
-        if (addresses) {
-                *dns = TAKE_PTR(addresses);
-
-                *n_dns = n_addresses;
-        }
+        *ret_addresses = TAKE_PTR(addresses);
+        *ret_size = n_addresses;
 
         return n_addresses;
 }
@@ -520,7 +547,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
 
         lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
 
-        r = radv_get_ip6dns(link->network, &dns, &n_dns);
+        r = network_get_ipv6_dns(link->network, &dns, &n_dns);
         if (r > 0)
                 goto set_dns;
 
@@ -530,7 +557,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
                         return 0;
                 }
 
-                r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
+                r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
                 if (r > 0)
                         goto set_dns;
         }
@@ -604,6 +631,15 @@ int radv_emit_dns(Link *link) {
         return 0;
 }
 
+static bool link_radv_enabled(Link *link) {
+        assert(link);
+
+        if (!link_ipv6ll_enabled(link))
+                return false;
+
+        return link->network->router_prefix_delegation;
+}
+
 int radv_configure(Link *link) {
         RoutePrefix *q;
         Prefix *p;
@@ -612,11 +648,14 @@ int radv_configure(Link *link) {
         assert(link);
         assert(link->network);
 
+        if (!link_radv_enabled(link))
+                return 0;
+
         r = sd_radv_new(&link->radv);
         if (r < 0)
                 return r;
 
-        r = sd_radv_attach_event(link->radv, NULL, 0);
+        r = sd_radv_attach_event(link->radv, link->manager->event, 0);
         if (r < 0)
                 return r;
 
@@ -650,33 +689,64 @@ int radv_configure(Link *link) {
                         return r;
         }
 
-        if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
-                LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
-                        r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
-                        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;
+        HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
+                r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
+                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;
+        }
 
-                LIST_FOREACH(route_prefixes, q, link->network->static_route_prefixes) {
-                        r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
-                        if (r == -EEXIST)
-                                continue;
-                        if (r < 0)
-                                return r;
-                }
+        HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
+                r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int radv_update_mac(Link *link) {
+        bool restart;
+        int r;
+
+        assert(link);
+
+        if (!link->radv)
+                return 0;
+
+        restart = sd_radv_is_running(link->radv);
+
+        r = sd_radv_stop(link->radv);
+        if (r < 0)
+                return r;
+
+        r = sd_radv_set_mac(link->radv, &link->mac);
+        if (r < 0)
+                return r;
+
+        if (restart) {
+                r = sd_radv_start(link->radv);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
 }
 
-int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
-                    uint32_t lifetime_preferred, uint32_t lifetime_valid) {
+int radv_add_prefix(
+                Link *link,
+                const struct in6_addr *prefix,
+                uint8_t prefix_len,
+                uint32_t lifetime_preferred,
+                uint32_t lifetime_valid) {
+
         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
         int r;
 
@@ -727,6 +797,12 @@ int config_parse_radv_dns(
         assert(lvalue);
         assert(rvalue);
 
+        if (isempty(rvalue)) {
+                n->n_router_dns = 0;
+                n->router_dns = mfree(n->router_dns);
+                return 0;
+        }
+
         for (const char *p = rvalue;;) {
                 _cleanup_free_ char *w = NULL;
                 union in_addr_union a;
@@ -788,6 +864,11 @@ int config_parse_radv_search_domains(
         assert(lvalue);
         assert(rvalue);
 
+        if (isempty(rvalue)) {
+                n->router_search_domains = ordered_set_free(n->router_search_domains);
+                return 0;
+        }
+
         for (const char *p = rvalue;;) {
                 _cleanup_free_ char *w = NULL, *idna = NULL;
 
@@ -811,7 +892,7 @@ int config_parse_radv_search_domains(
                         /* transfer ownership to simplify subsequent operations */
                         idna = TAKE_PTR(w);
 
-                r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
+                r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
                 if (r < 0)
                         return log_oom();
 
@@ -822,10 +903,10 @@ int config_parse_radv_search_domains(
 }
 
 static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
-        [RADV_PREFIX_DELEGATION_NONE] = "no",
+        [RADV_PREFIX_DELEGATION_NONE]   = "no",
         [RADV_PREFIX_DELEGATION_STATIC] = "static",
-        [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
-        [RADV_PREFIX_DELEGATION_BOTH] = "yes",
+        [RADV_PREFIX_DELEGATION_DHCP6]  = "dhcpv6",
+        [RADV_PREFIX_DELEGATION_BOTH]   = "yes",
 };
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
@@ -833,21 +914,64 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
                 RADVPrefixDelegation,
                 RADV_PREFIX_DELEGATION_BOTH);
 
-DEFINE_CONFIG_PARSE_ENUM(config_parse_router_prefix_delegation,
-                         radv_prefix_delegation,
-                         RADVPrefixDelegation,
-                         "Invalid router prefix delegation");
-
-int config_parse_router_preference(const char *unit,
-                                   const char *filename,
-                                   unsigned line,
-                                   const char *section,
-                                   unsigned section_line,
-                                   const char *lvalue,
-                                   int ltype,
-                                   const char *rvalue,
-                                   void *data,
-                                   void *userdata) {
+int config_parse_router_prefix_delegation(
+                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) {
+
+        RADVPrefixDelegation val, *ra = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (streq(lvalue, "IPv6SendRA")) {
+                r = parse_boolean(rvalue);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
+                                   "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
+                        return 0;
+                }
+
+                /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
+                 * need to explicitly enable DHCPv6PrefixDelegation=. */
+                *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
+                return 0;
+        }
+
+        /* For backward compatibility */
+        val = radv_prefix_delegation_from_string(rvalue);
+        if (val < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        *ra = val;
+        return 0;
+}
+
+int config_parse_router_preference(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = userdata;
 
         assert(filename);
index 496ef97adcf6cca844e2a0b821138d39e78ae243..75c606d15e2afdebe7a4a05ef9ceef5fd8736c57 100644 (file)
@@ -5,13 +5,17 @@
   Copyright © 2017 Intel Corporation. All rights reserved.
 ***/
 
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "sd-radv.h"
+
+#include "in-addr-util.h"
 #include "conf-parser.h"
-#include "networkd-address.h"
-#include "networkd-link.h"
 #include "networkd-util.h"
 
-typedef struct Prefix Prefix;
-typedef struct RoutePrefix RoutePrefix;
+typedef struct Network Network;
+typedef struct Link Link;
 
 typedef enum RADVPrefixDelegation {
         RADV_PREFIX_DELEGATION_NONE   = 0,
@@ -22,36 +26,32 @@ typedef enum RADVPrefixDelegation {
         _RADV_PREFIX_DELEGATION_INVALID = -1,
 } RADVPrefixDelegation;
 
-struct Prefix {
+typedef struct Prefix {
         Network *network;
         NetworkConfigSection *section;
 
         sd_radv_prefix *radv_prefix;
 
         bool assign;
+} Prefix;
 
-        LIST_FIELDS(Prefix, prefixes);
-};
-
-struct RoutePrefix {
+typedef struct RoutePrefix {
         Network *network;
         NetworkConfigSection *section;
 
         sd_radv_route_prefix *radv_route_prefix;
+} RoutePrefix;
 
-        LIST_FIELDS(RoutePrefix, route_prefixes);
-};
-
-void prefix_free(Prefix *prefix);
-
-DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
-
-void route_prefix_free(RoutePrefix *prefix);
+Prefix *prefix_free(Prefix *prefix);
+RoutePrefix *route_prefix_free(RoutePrefix *prefix);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
+void network_drop_invalid_prefixes(Network *network);
+void network_drop_invalid_route_prefixes(Network *network);
+void network_adjust_radv(Network *network);
 
 int radv_emit_dns(Link *link);
 int radv_configure(Link *link);
+int radv_update_mac(Link *link);
 int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
                     uint32_t lifetime_preferred, uint32_t lifetime_valid);
 
index b82c4e7f79e2b07b68af557719d5e0f87e794428..dd05e11067be05ec5a8db6f02b52b9265b9f2795 100644 (file)
@@ -1,18 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <linux/icmpv6.h>
+#include <linux/ipv6_route.h>
 
 #include "alloc-util.h"
-#include "conf-parser.h"
-#include "in-addr-util.h"
-#include "missing_network.h"
 #include "netlink-util.h"
 #include "networkd-ipv4ll.h"
 #include "networkd-manager.h"
-#include "networkd-ndisc.h"
+#include "networkd-network.h"
+#include "networkd-nexthop.h"
 #include "networkd-route.h"
+#include "networkd-routing-policy-rule.h"
 #include "parse-util.h"
-#include "set.h"
 #include "socket-netlink.h"
 #include "string-table.h"
 #include "string-util.h"
 
 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
 
+static uint32_t link_get_vrf_table(const Link *link) {
+        return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
+}
+
+uint32_t link_get_dhcp_route_table(const Link *link) {
+        /* When the interface is part of an VRF use the VRFs routing table, unless
+         * another table is explicitly specified. */
+        if (link->network->dhcp_route_table_set)
+                return link->network->dhcp_route_table;
+        return link_get_vrf_table(link);
+}
+
+uint32_t link_get_ipv6_accept_ra_route_table(const Link *link) {
+        if (link->network->ipv6_accept_ra_route_table_set)
+                return link->network->ipv6_accept_ra_route_table;
+        return link_get_vrf_table(link);
+}
+
+static const char * const route_type_table[__RTN_MAX] = {
+        [RTN_UNICAST]     = "unicast",
+        [RTN_LOCAL]       = "local",
+        [RTN_BROADCAST]   = "broadcast",
+        [RTN_ANYCAST]     = "anycast",
+        [RTN_MULTICAST]   = "multicast",
+        [RTN_BLACKHOLE]   = "blackhole",
+        [RTN_UNREACHABLE] = "unreachable",
+        [RTN_PROHIBIT]    = "prohibit",
+        [RTN_THROW]       = "throw",
+        [RTN_NAT]         = "nat",
+        [RTN_XRESOLVE]    = "xresolve",
+};
+
+assert_cc(__RTN_MAX <= UCHAR_MAX);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type, int);
+
+static const char * const route_scope_table[] = {
+        [RT_SCOPE_UNIVERSE] = "global",
+        [RT_SCOPE_SITE]     = "site",
+        [RT_SCOPE_LINK]     = "link",
+        [RT_SCOPE_HOST]     = "host",
+        [RT_SCOPE_NOWHERE]  = "nowhere",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
+
+#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
+static const char *format_route_scope(int scope, char *buf, size_t size) {
+        const char *s;
+        char *p = buf;
+
+        s = route_scope_to_string(scope);
+        if (s)
+                strpcpy(&p, size, s);
+        else
+                strpcpyf(&p, size, "%d", scope);
+
+        return buf;
+}
+
+static const char * const route_table_table[] = {
+        [RT_TABLE_DEFAULT] = "default",
+        [RT_TABLE_MAIN]    = "main",
+        [RT_TABLE_LOCAL]   = "local",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
+
+#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
+static const char *format_route_table(int table, char *buf, size_t size) {
+        const char *s;
+        char *p = buf;
+
+        s = route_table_to_string(table);
+        if (s)
+                strpcpy(&p, size, s);
+        else
+                strpcpyf(&p, size, "%d", table);
+
+        return buf;
+}
+
+static const char * const route_protocol_table[] = {
+        [RTPROT_KERNEL] = "kernel",
+        [RTPROT_BOOT]   = "boot",
+        [RTPROT_STATIC] = "static",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
+
+static const char * const route_protocol_full_table[] = {
+        [RTPROT_REDIRECT] = "redirect",
+        [RTPROT_KERNEL]   = "kernel",
+        [RTPROT_BOOT]     = "boot",
+        [RTPROT_STATIC]   = "static",
+        [RTPROT_GATED]    = "gated",
+        [RTPROT_RA]       = "ra",
+        [RTPROT_MRT]      = "mrt",
+        [RTPROT_ZEBRA]    = "zebra",
+        [RTPROT_BIRD]     = "bird",
+        [RTPROT_DNROUTED] = "dnrouted",
+        [RTPROT_XORP]     = "xorp",
+        [RTPROT_NTK]      = "ntk",
+        [RTPROT_DHCP]     = "dhcp",
+        [RTPROT_MROUTED]  = "mrouted",
+        [RTPROT_BABEL]    = "babel",
+        [RTPROT_BGP]      = "bgp",
+        [RTPROT_ISIS]     = "isis",
+        [RTPROT_OSPF]     = "ospf",
+        [RTPROT_RIP]      = "rip",
+        [RTPROT_EIGRP]    = "eigrp",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
+
+#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
+static const char *format_route_protocol(int protocol, char *buf, size_t size) {
+        const char *s;
+        char *p = buf;
+
+        s = route_protocol_full_to_string(protocol);
+        if (s)
+                strpcpy(&p, size, s);
+        else
+                strpcpyf(&p, size, "%d", protocol);
+
+        return buf;
+}
+
 static unsigned routes_max(void) {
         static thread_local unsigned cached = 0;
 
@@ -82,22 +209,20 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
 
         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;
+        assert(filename);
+        assert(section_line > 0);
 
-                route = hashmap_get(network->routes_by_section, n);
-                if (route) {
-                        *ret = TAKE_PTR(route);
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                        return 0;
-                }
+        route = hashmap_get(network->routes_by_section, n);
+        if (route) {
+                *ret = TAKE_PTR(route);
+                return 0;
         }
 
-        if (network->n_static_routes >= routes_max())
+        if (hashmap_size(network->routes_by_section) >= routes_max())
                 return -E2BIG;
 
         r = route_new(&route);
@@ -106,38 +231,27 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
 
         route->protocol = RTPROT_STATIC;
         route->network = network;
-        LIST_PREPEND(routes, network->static_routes, route);
-        network->n_static_routes++;
-
-        if (filename) {
-                route->section = TAKE_PTR(n);
+        route->section = TAKE_PTR(n);
 
-                r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
+        r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
 
-                r = hashmap_put(network->routes_by_section, route->section, route);
-                if (r < 0)
-                        return r;
-        }
+        r = hashmap_put(network->routes_by_section, route->section, route);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(route);
-
         return 0;
 }
 
-void route_free(Route *route) {
+Route *route_free(Route *route) {
         if (!route)
-                return;
+                return NULL;
 
         if (route->network) {
-                LIST_REMOVE(routes, route->network->static_routes, route);
-
-                assert(route->network->n_static_routes > 0);
-                route->network->n_static_routes--;
-
-                if (route->section)
-                        hashmap_remove(route->network->routes_by_section, route->section);
+                assert(route->section);
+                hashmap_remove(route->network->routes_by_section, route->section);
         }
 
         network_config_section_free(route->section);
@@ -158,11 +272,16 @@ void route_free(Route *route) {
                                 free(set_remove(route->link->ndisc_routes, n));
         }
 
+        if (route->manager) {
+                set_remove(route->manager->routes, route);
+                set_remove(route->manager->routes_foreign, route);
+        }
+
         ordered_set_free_free(route->multipath_routes);
 
         sd_event_source_unref(route->expire);
 
-        free(route);
+        return mfree(route);
 }
 
 void route_hash_func(const Route *route, struct siphash *state) {
@@ -179,7 +298,11 @@ void route_hash_func(const Route *route, struct siphash *state) {
                 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
                 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
 
-                siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
+                siphash24_compress(&route->gw_family, sizeof(route->gw_family), state);
+                if (IN_SET(route->gw_family, AF_INET, AF_INET6)) {
+                        siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->gw_family), state);
+                        siphash24_compress(&route->gw_weight, sizeof(route->gw_weight), state);
+                }
 
                 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
 
@@ -226,10 +349,20 @@ int route_compare_func(const Route *a, const Route *b) {
                 if (r != 0)
                         return r;
 
-                r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
+                r = CMP(a->gw_family, b->gw_family);
                 if (r != 0)
                         return r;
 
+                if (IN_SET(a->gw_family, AF_INET, AF_INET6)) {
+                        r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
+                        if (r != 0)
+                                return r;
+
+                        r = CMP(a->gw_weight, b->gw_weight);
+                        if (r != 0)
+                                return r;
+                }
+
                 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
                 if (r != 0)
                         return r;
@@ -280,7 +413,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 route_compare_func,
                 route_free);
 
-bool route_equal(Route *r1, Route *r2) {
+static bool route_equal(const Route *r1, const Route *r2) {
         if (r1 == r2)
                 return true;
 
@@ -290,36 +423,81 @@ bool route_equal(Route *r1, Route *r2) {
         return route_compare_func(r1, r2) == 0;
 }
 
-int route_get(Link *link, Route *in, Route **ret) {
-
+static int route_get(const Manager *manager, const Link *link, const Route *in, Route **ret) {
         Route *existing;
 
-        assert(link);
+        assert(manager || link);
         assert(in);
 
-        existing = set_get(link->routes, in);
-        if (existing) {
-                if (ret)
-                        *ret = existing;
-                return 1;
-        }
+        if (link) {
+                existing = set_get(link->routes, in);
+                if (existing) {
+                        if (ret)
+                                *ret = existing;
+                        return 1;
+                }
 
-        existing = set_get(link->routes_foreign, in);
-        if (existing) {
-                if (ret)
-                        *ret = existing;
-                return 0;
+                existing = set_get(link->routes_foreign, in);
+                if (existing) {
+                        if (ret)
+                                *ret = existing;
+                        return 0;
+                }
+        } else {
+                existing = set_get(manager->routes, in);
+                if (existing) {
+                        if (ret)
+                                *ret = existing;
+                        return 1;
+                }
+
+                existing = set_get(manager->routes_foreign, in);
+                if (existing) {
+                        if (ret)
+                                *ret = existing;
+                        return 0;
+                }
         }
 
         return -ENOENT;
 }
 
-static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
+static void route_copy(Route *dest, const Route *src, const MultipathRoute *m) {
+        assert(dest);
+        assert(src);
+
+        dest->family = src->family;
+        dest->src = src->src;
+        dest->src_prefixlen = src->src_prefixlen;
+        dest->dst = src->dst;
+        dest->dst_prefixlen = src->dst_prefixlen;
+        dest->prefsrc = src->prefsrc;
+        dest->scope = src->scope;
+        dest->protocol = src->protocol;
+        dest->type = src->type;
+        dest->tos = src->tos;
+        dest->priority = src->priority;
+        dest->table = src->table;
+        dest->initcwnd = src->initcwnd;
+        dest->initrwnd = src->initrwnd;
+        dest->lifetime = src->lifetime;
+
+        if (m) {
+                dest->gw_family = m->gateway.family;
+                dest->gw = m->gateway.address;
+                dest->gw_weight = m->weight;
+        } else {
+                dest->gw_family = src->gw_family;
+                dest->gw = src->gw;
+                dest->gw_weight = src->gw_weight;
+        }
+}
 
+static int route_add_internal(Manager *manager, Link *link, Set **routes, const Route *in, Route **ret) {
         _cleanup_(route_freep) Route *route = NULL;
         int r;
 
-        assert(link);
+        assert(manager || link);
         assert(routes);
         assert(in);
 
@@ -327,22 +505,7 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
         if (r < 0)
                 return r;
 
-        route->family = in->family;
-        route->src = in->src;
-        route->src_prefixlen = in->src_prefixlen;
-        route->dst = in->dst;
-        route->dst_prefixlen = in->dst_prefixlen;
-        route->gw = in->gw;
-        route->prefsrc = in->prefsrc;
-        route->scope = in->scope;
-        route->protocol = in->protocol;
-        route->type = in->type;
-        route->tos = in->tos;
-        route->priority = in->priority;
-        route->table = in->table;
-        route->initcwnd = in->initcwnd;
-        route->initrwnd = in->initrwnd;
-        route->lifetime = in->lifetime;
+        route_copy(route, in, NULL);
 
         r = set_ensure_put(routes, &route_hash_ops, route);
         if (r < 0)
@@ -351,6 +514,7 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
                 return -EEXIST;
 
         route->link = link;
+        route->manager = manager;
 
         if (ret)
                 *ret = route;
@@ -360,28 +524,51 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
         return 0;
 }
 
-int route_add_foreign(Link *link, Route *in, Route **ret) {
-        return route_add_internal(link, &link->routes_foreign, in, ret);
+static int route_add_foreign(Manager *manager, Link *link, const Route *in, Route **ret) {
+        assert(manager || link);
+        return route_add_internal(manager, link, link ? &link->routes_foreign : &manager->routes_foreign, in, ret);
 }
 
-int route_add(Link *link, Route *in, Route **ret) {
-
+static int route_add(Manager *manager, Link *link, const Route *in, const MultipathRoute *m, Route **ret) {
+        _cleanup_(route_freep) Route *tmp = NULL;
         Route *route;
         int r;
 
-        r = route_get(link, in, &route);
+        assert(manager || link);
+        assert(in);
+
+        if (m) {
+                assert(link && (m->ifindex == 0 || m->ifindex == link->ifindex));
+
+                r = route_new(&tmp);
+                if (r < 0)
+                        return r;
+
+                route_copy(tmp, in, m);
+                in = tmp;
+        }
+
+        r = route_get(manager, link, in, &route);
         if (r == -ENOENT) {
                 /* Route does not exist, create a new one */
-                r = route_add_internal(link, &link->routes, in, &route);
+                r = route_add_internal(manager, link, link ? &link->routes : &manager->routes, in, &route);
                 if (r < 0)
                         return r;
         } else if (r == 0) {
                 /* Take over a foreign route */
-                r = set_ensure_put(&link->routes, &route_hash_ops, route);
-                if (r < 0)
-                        return r;
+                if (link) {
+                        r = set_ensure_put(&link->routes, &route_hash_ops, route);
+                        if (r < 0)
+                                return r;
+
+                        set_remove(link->routes_foreign, route);
+                } else {
+                        r = set_ensure_put(&manager->routes, &route_hash_ops, route);
+                        if (r < 0)
+                                return r;
 
-                set_remove(link->routes_foreign, route);
+                        set_remove(manager->routes_foreign, route);
+                }
         } else if (r == 1) {
                 /* Route exists, do nothing */
                 ;
@@ -398,10 +585,9 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
         int r;
 
         assert(m);
-        assert(link);
-        assert(link->ifname);
 
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+        /* Note that link may be NULL. */
+        if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
         r = sd_netlink_message_get_errno(m);
@@ -411,19 +597,23 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
         return 1;
 }
 
-int route_remove(Route *route, Link *link,
-                 link_netlink_message_handler_t callback) {
+int route_remove(
+                const Route *route,
+                Manager *manager,
+                Link *link,
+                link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
-        assert(link);
-        assert(link->manager);
-        assert(link->manager->rtnl);
-        assert(link->ifindex > 0);
+        assert(link || manager);
         assert(IN_SET(route->family, AF_INET, AF_INET6));
 
-        r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
+        if (!manager)
+                manager = link->manager;
+        /* link may be NULL! */
+
+        r = sd_rtnl_message_new_route(manager->rtnl, &req,
                                       RTM_DELROUTE, route->family,
                                       route->protocol);
         if (r < 0)
@@ -439,8 +629,8 @@ int route_remove(Route *route, Link *link,
                 }
                 if (!in_addr_is_null(route->family, &route->src))
                         (void) in_addr_to_string(route->family, &route->src, &src);
-                if (!in_addr_is_null(route->family, &route->gw))
-                        (void) in_addr_to_string(route->family, &route->gw, &gw);
+                if (!in_addr_is_null(route->gw_family, &route->gw))
+                        (void) in_addr_to_string(route->gw_family, &route->gw, &gw);
                 if (!in_addr_is_null(route->family, &route->prefsrc))
                         (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
 
@@ -452,10 +642,21 @@ int route_remove(Route *route, Link *link,
                                strna(route_type_to_string(route->type)));
         }
 
-        if (in_addr_is_null(route->family, &route->gw) == 0) {
-                r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
+        if (in_addr_is_null(route->gw_family, &route->gw) == 0) {
+                if (route->gw_family == route->family) {
+                        r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
+                } else {
+                        RouteVia rtvia = {
+                                .family = route->gw_family,
+                                .address = route->gw,
+                        };
+
+                        r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Could not append RTA_VIA attribute: %m");
+                }
         }
 
         if (route->dst_prefixlen) {
@@ -493,6 +694,8 @@ int route_remove(Route *route, Link *link,
                 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
 
         if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
+                assert(link); /* Those routes must be attached to a specific link */
+
                 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
@@ -504,27 +707,142 @@ int route_remove(Route *route, Link *link,
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
-        link_ref(link);
+        link_ref(link); /* link may be NULL, link_ref() is OK with that */
 
         return 0;
 }
 
-int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+static bool link_is_static_route_configured(const Link *link, const Route *route) {
+        Route *net_route;
+
+        assert(link);
+        assert(route);
+
+        if (!link->network)
+                return false;
+
+        HASHMAP_FOREACH(net_route, link->network->routes_by_section)
+                if (route_equal(net_route, route))
+                        return true;
+
+        return false;
+}
+
+int link_drop_foreign_routes(Link *link) {
+        Route *route;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(route, link->routes_foreign) {
+                /* do not touch routes managed by the kernel */
+                if (route->protocol == RTPROT_KERNEL)
+                        continue;
+
+                /* do not touch multicast route added by kernel */
+                /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
+                 * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
+                if (route->protocol == RTPROT_BOOT &&
+                    route->family == AF_INET6 &&
+                    route->dst_prefixlen == 8 &&
+                    in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
+                        continue;
+
+                if (route->protocol == RTPROT_STATIC && link->network &&
+                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+                        continue;
+
+                if (route->protocol == RTPROT_DHCP && link->network &&
+                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+                        continue;
+
+                if (link_is_static_route_configured(link, route))
+                        k = route_add(NULL, link, route, NULL, NULL);
+                else
+                        k = route_remove(route, NULL, link, NULL);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+int link_drop_routes(Link *link) {
+        Route *route;
+        int k, r = 0;
+
+        assert(link);
+
+        SET_FOREACH(route, link->routes) {
+                /* do not touch routes managed by the kernel */
+                if (route->protocol == RTPROT_KERNEL)
+                        continue;
+
+                k = route_remove(route, NULL, link, NULL);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
         Route *route = userdata;
         int r;
 
         assert(route);
 
-        r = route_remove(route, route->link, NULL);
-        if (r < 0)
+        r = route_remove(route, route->manager, route->link, NULL);
+        if (r < 0) {
                 log_link_warning_errno(route->link, r, "Could not remove route: %m");
-        else
                 route_free(route);
+        }
 
         return 1;
 }
 
-static int append_nexthop_one(Route *route, MultipathRoute *m, struct rtattr **rta, size_t offset) {
+static int route_add_and_setup_timer(Link *link, const Route *route, const MultipathRoute *m, Route **ret) {
+        _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
+        Route *nr;
+        int r;
+
+        assert(link);
+        assert(route);
+
+        if (IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW))
+                r = route_add(link->manager, NULL, route, NULL, &nr);
+        else if (!m || m->ifindex == 0 || m->ifindex == link->ifindex)
+                r = route_add(NULL, link, route, m, &nr);
+        else {
+                Link *link_gw;
+
+                r = link_get(link->manager, m->ifindex, &link_gw);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Failed to get link with ifindex %d: %m", m->ifindex);
+
+                r = route_add(NULL, link_gw, route, m, &nr);
+        }
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not add route: %m");
+
+        /* TODO: drop expiration handling once it can be pushed into the kernel */
+        if (nr->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
+                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
+                                      nr->lifetime, 0, route_expire_handler, nr);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
+        }
+
+        sd_event_source_unref(nr->expire);
+        nr->expire = TAKE_PTR(expire);
+
+        if (ret)
+                *ret = nr;
+
+        return 0;
+}
+
+static int append_nexthop_one(const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
         struct rtnexthop *rtnh;
         struct rtattr *new_rta;
         int r;
@@ -569,7 +887,7 @@ clear:
         return r;
 }
 
-static int append_nexthops(Route *route, sd_netlink_message *req) {
+static int append_nexthops(const Route *route, sd_netlink_message *req) {
         _cleanup_free_ struct rtattr *rta = NULL;
         struct rtnexthop *rtnh;
         MultipathRoute *m;
@@ -606,13 +924,13 @@ static int append_nexthops(Route *route, sd_netlink_message *req) {
 }
 
 int route_configure(
-                Route *route,
+                const Route *route,
                 Link *link,
                 link_netlink_message_handler_t callback,
                 Route **ret) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
+        unsigned flags;
         int r;
 
         assert(link);
@@ -622,7 +940,7 @@ int route_configure(
         assert(IN_SET(route->family, AF_INET, AF_INET6));
         assert(callback);
 
-        if (route_get(link, route, NULL) <= 0 &&
+        if (route_get(link->manager, link, route, NULL) <= 0 &&
             set_size(link->routes) >= routes_max())
                 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
                                             "Too many routes are configured, refusing: %m");
@@ -637,8 +955,8 @@ int route_configure(
                 }
                 if (!in_addr_is_null(route->family, &route->src))
                         (void) in_addr_to_string(route->family, &route->src, &src);
-                if (!in_addr_is_null(route->family, &route->gw))
-                        (void) in_addr_to_string(route->family, &route->gw, &gw);
+                if (!in_addr_is_null(route->gw_family, &route->gw))
+                        (void) in_addr_to_string(route->gw_family, &route->gw, &gw);
                 if (!in_addr_is_null(route->family, &route->prefsrc))
                         (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
 
@@ -656,14 +974,21 @@ int route_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
 
-        if (in_addr_is_null(route->family, &route->gw) == 0) {
-                r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
+        if (in_addr_is_null(route->gw_family, &route->gw) == 0) {
+                if (route->gw_family == route->family) {
+                        r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
+                } else {
+                        RouteVia rtvia = {
+                                .family = route->gw_family,
+                                .address = route->gw,
+                        };
 
-                r = sd_rtnl_message_route_set_family(req, route->family);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set route family: %m");
+                        r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Could not append RTA_VIA attribute: %m");
+                }
         }
 
         if (route->dst_prefixlen > 0) {
@@ -696,10 +1021,11 @@ int route_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set scope: %m");
 
+        flags = route->flags;
         if (route->gateway_onlink >= 0)
-                SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
+                SET_FLAG(flags, RTNH_F_ONLINK, route->gateway_onlink);
 
-        r = sd_rtnl_message_route_set_flags(req, route->flags);
+        r = sd_rtnl_message_route_set_flags(req, flags);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set flags: %m");
 
@@ -720,109 +1046,601 @@ int route_configure(
                 }
         }
 
-        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
+        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
+
+        r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
+
+        if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
+                r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
+                        DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
+        }
+
+        r = sd_rtnl_message_route_set_type(req, route->type);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not set route type: %m");
+
+        if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
+                r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
+        }
+
+        if (route->ttl_propagate >= 0) {
+                r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
+        }
+
+        r = sd_netlink_message_open_container(req, RTA_METRICS);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
+
+        if (route->mtu > 0) {
+                r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
+        }
+
+        if (route->initcwnd > 0) {
+                r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
+        }
+
+        if (route->initrwnd > 0) {
+                r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
+        }
+
+        if (route->quickack >= 0) {
+                r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
+        }
+
+        if (route->fast_open_no_cookie >= 0) {
+                r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
+        }
+
+        r = sd_netlink_message_close_container(req);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
+
+        r = append_nexthops(route, req);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
+
+        if (ordered_set_isempty(route->multipath_routes)) {
+                Route *nr;
+
+                r = route_add_and_setup_timer(link, route, NULL, &nr);
+                if (r < 0)
+                        return r;
+
+                if (ret)
+                        *ret = nr;
+        } else {
+                MultipathRoute *m;
+
+                assert(!ret);
+
+                ORDERED_SET_FOREACH(m, route->multipath_routes) {
+                        r = route_add_and_setup_timer(link, route, m, NULL);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+        link_ref(link);
+
+        return 0;
+}
+
+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_CONFIGURING,
+                      LINK_STATE_FAILED, LINK_STATE_LINGER));
+
+        link->route_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_message_warning_errno(link, m, r, "Could not set route");
+                link_enter_failed(link);
+                return 1;
+        }
+
+        if (link->route_messages == 0) {
+                log_link_debug(link, "Routes set");
+                link->static_routes_configured = true;
+                link_set_nexthop(link);
+        }
+
+        return 1;
+}
+
+int link_set_routes(Link *link) {
+        enum {
+                PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
+                PHASE_GATEWAY,     /* Second phase: Routes with a gateway */
+                _PHASE_MAX
+        } phase;
+        Route *rt;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->state != _LINK_STATE_INVALID);
+
+        link->static_routes_configured = false;
+
+        if (!link->addresses_ready)
+                return 0;
+
+        if (!link_has_carrier(link) && !link->network->configure_without_carrier)
+                /* During configuring addresses, the link lost its carrier. As networkd is dropping
+                 * the addresses now, let's not configure the routes either. */
+                return 0;
+
+        r = link_set_routing_policy_rules(link);
+        if (r < 0)
+                return r;
+
+        /* 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++)
+                HASHMAP_FOREACH(rt, link->network->routes_by_section) {
+                        if (rt->gateway_from_dhcp_or_ra)
+                                continue;
+
+                        if ((in_addr_is_null(rt->gw_family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
+                                continue;
+
+                        r = route_configure(rt, link, route_handler, NULL);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not set routes: %m");
+
+                        link->route_messages++;
+                }
+
+        if (link->route_messages == 0) {
+                link->static_routes_configured = true;
+                link_set_nexthop(link);
+        } else {
+                log_link_debug(link, "Setting routes");
+                link_set_state(link, LINK_STATE_CONFIGURING);
+        }
+
+        return 0;
+}
+
+static int process_route_one(Manager *manager, Link *link, uint16_t type, const Route *tmp, const MultipathRoute *m) {
+        _cleanup_(route_freep) Route *nr = NULL;
+        Route *route = NULL;
+        int r;
+
+        assert(manager);
+        assert(tmp);
+        assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
+
+        if (m) {
+                if (link)
+                        return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL),
+                                                "rtnl: received route contains both RTA_OIF and RTA_MULTIPATH, ignoring.");
+
+                if (m->ifindex <= 0)
+                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                 "rtnl: received multipath route with invalid ifindex, ignoring.");
+
+                r = link_get(manager, m->ifindex, &link);
+                if (r < 0) {
+                        log_warning_errno(r, "rtnl: received multipath route for link (%d) we do not know, ignoring: %m", m->ifindex);
+                        return 0;
+                }
+
+                r = route_new(&nr);
+                if (r < 0)
+                        return log_oom();
+
+                route_copy(nr, tmp, m);
+
+                tmp = nr;
+        }
+
+        (void) route_get(manager, link, tmp, &route);
+
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
+                        *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
+                char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
+                        buf_protocol[ROUTE_PROTOCOL_STR_MAX];
+
+                if (!in_addr_is_null(tmp->family, &tmp->dst)) {
+                        (void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
+                        (void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
+                }
+                if (!in_addr_is_null(tmp->family, &tmp->src))
+                        (void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
+                if (!in_addr_is_null(tmp->gw_family, &tmp->gw))
+                        (void) in_addr_to_string(tmp->gw_family, &tmp->gw, &buf_gw);
+                if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
+                        (void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
+
+                log_link_debug(link,
+                               "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
+                               (!route && !manager->manage_foreign_routes) ? "Ignoring received foreign" :
+                               type == RTM_DELROUTE ? "Forgetting" :
+                               route ? "Received remembered" : "Remembering",
+                               strna(buf_dst), strempty(buf_dst_prefixlen),
+                               strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
+                               format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
+                               format_route_table(tmp->table, buf_table, sizeof buf_table),
+                               format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
+                               strna(route_type_to_string(tmp->type)));
+        }
+
+        switch (type) {
+        case RTM_NEWROUTE:
+                if (!route && manager->manage_foreign_routes) {
+                        /* A route appeared that we did not request */
+                        r = route_add_foreign(manager, link, tmp, NULL);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
+                                return 0;
+                        }
+                }
+
+                break;
+
+        case RTM_DELROUTE:
+                route_free(route);
+                break;
+
+        default:
+                assert_not_reached("Received route message with invalid RTNL message type");
+        }
+
+        return 1;
+}
+
+int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
+        _cleanup_ordered_set_free_free_ OrderedSet *multipath_routes = NULL;
+        _cleanup_(route_freep) Route *tmp = NULL;
+        _cleanup_free_ void *rta_multipath = NULL;
+        Link *link = NULL;
+        uint32_t ifindex;
+        uint16_t type;
+        unsigned char table;
+        RouteVia via;
+        size_t rta_len;
+        int r;
+
+        assert(rtnl);
+        assert(message);
+        assert(m);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
+
+                return 0;
+        }
+
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
+                log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
+                return 0;
+        } else if (r >= 0) {
+                if (ifindex <= 0) {
+                        log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
+                        return 0;
+                }
+
+                r = link_get(m, ifindex, &link);
+                if (r < 0 || !link) {
+                        /* when enumerating we might be out of sync, but we will
+                         * get the route again, so just ignore it */
+                        if (!m->enumerating)
+                                log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
+                        return 0;
+                }
+        }
+
+        r = route_new(&tmp);
+        if (r < 0)
+                return log_oom();
+
+        r = sd_rtnl_message_route_get_family(message, &tmp->family);
+        if (r < 0) {
+                log_link_warning(link, "rtnl: received route message without family, ignoring");
+                return 0;
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: received route message without route protocol: %m");
+                return 0;
+        }
+
+        switch (tmp->family) {
+        case AF_INET:
+                r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
+                        return 0;
+                } else if (r >= 0)
+                        tmp->gw_family = AF_INET;
+
+                r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        tmp->gw_family = via.family;
+                        tmp->gw = via.address;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        case AF_INET6:
+                r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
+                        return 0;
+                } else if (r >= 0)
+                        tmp->gw_family = AF_INET6;
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        default:
+                assert_not_reached("Received route message with unsupported address family");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
+                return 0;
+        }
 
-        r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
+        r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
+                return 0;
+        }
 
-        if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
-                r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
-                        DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
+        r = sd_rtnl_message_route_get_type(message, &tmp->type);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
+                return 0;
         }
 
-        r = sd_rtnl_message_route_set_type(req, route->type);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not set route type: %m");
+        r = sd_rtnl_message_route_get_table(message, &table);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
+                return 0;
+        }
+        tmp->table = table;
 
-        if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
-                r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
+        r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
+                return 0;
         }
 
-        if (route->ttl_propagate >= 0) {
-                r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
+        r = sd_netlink_message_enter_container(message, RTA_METRICS);
+        if (r < 0 && r != -ENODATA) {
+                log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
+                return 0;
         }
+        if (r >= 0) {
+                r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
+                        return 0;
+                }
 
-        r = sd_netlink_message_open_container(req, RTA_METRICS);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
+                r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
+                        return 0;
+                }
 
-        if (route->mtu > 0) {
-                r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
+                r = sd_netlink_message_exit_container(message);
+                if (r < 0) {
+                        log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
+                        return 0;
+                }
         }
 
-        if (route->initcwnd > 0) {
-                r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
+        r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
+                return 0;
+        } else if (r >= 0) {
+                r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &multipath_routes);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
+                        return 0;
+                }
         }
 
-        if (route->initrwnd > 0) {
-                r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
-        }
+        if (ordered_set_isempty(multipath_routes))
+                (void) process_route_one(m, link, type, tmp, NULL);
+        else {
+                MultipathRoute *mr;
 
-        if (route->quickack >= 0) {
-                r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
+                ORDERED_SET_FOREACH(mr, multipath_routes) {
+                        r = process_route_one(m, link, type, tmp, mr);
+                        if (r < 0)
+                                break;
+                }
         }
 
-        if (route->fast_open_no_cookie >= 0) {
-                r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
+        return 1;
+}
+
+int link_serialize_routes(const Link *link, FILE *f) {
+        bool space = false;
+        Route *route;
+
+        assert(link);
+        assert(link->network);
+        assert(f);
+
+        fputs("ROUTES=", f);
+        SET_FOREACH(route, link->routes) {
+                _cleanup_free_ char *route_str = NULL;
+
+                if (in_addr_to_string(route->family, &route->dst, &route_str) < 0)
+                        continue;
+
+                fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
+                        space ? " " : "", route_str,
+                        route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
+                space = true;
         }
+        fputc('\n', f);
 
-        r = sd_netlink_message_close_container(req);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
+        return 0;
+}
 
-        r = append_nexthops(route, req);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
+int link_deserialize_routes(Link *link, const char *routes) {
+        int r;
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
-                               link_netlink_destroy_callback, link);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+        assert(link);
 
-        link_ref(link);
+        for (const char *p = routes;; ) {
+                _cleanup_(route_freep) Route *tmp = NULL;
+                _cleanup_free_ char *route_str = NULL;
+                char *prefixlen_str;
 
-        r = route_add(link, route, &route);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not add route: %m");
+                r = extract_first_word(&p, &route_str, NULL, 0);
+                if (r < 0)
+                        return log_link_debug_errno(link, r, "Failed to parse ROUTES=: %m");
+                if (r == 0)
+                        return 0;
 
-        /* TODO: drop expiration handling once it can be pushed into the kernel */
-        if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
-                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
-                                      route->lifetime, 0, route_expire_handler, route);
+                prefixlen_str = strchr(route_str, '/');
+                if (!prefixlen_str) {
+                        log_link_debug(link, "Failed to parse route, ignoring: %s", route_str);
+                        continue;
+                }
+                *prefixlen_str++ = '\0';
+
+                r = route_new(&tmp);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
-        }
+                        return log_oom();
 
-        sd_event_source_unref(route->expire);
-        route->expire = TAKE_PTR(expire);
+                r = sscanf(prefixlen_str,
+                           "%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
+                           &tmp->dst_prefixlen,
+                           &tmp->tos,
+                           &tmp->priority,
+                           &tmp->table,
+                           &tmp->lifetime);
+                if (r != 5) {
+                        log_link_debug(link,
+                                       "Failed to parse destination prefix length, tos, priority, table or expiration: %s",
+                                       prefixlen_str);
+                        continue;
+                }
 
-        if (ret)
-                *ret = route;
+                r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
+                if (r < 0) {
+                        log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
+                        continue;
+                }
 
-        return 1;
+                r = route_add_and_setup_timer(link, tmp, NULL, NULL);
+                if (r < 0)
+                        return log_link_debug_errno(link, r, "Failed to add route: %m");
+        }
 }
 
 int network_add_ipv4ll_route(Network *network) {
         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
+        unsigned section_line;
         int r;
 
         assert(network);
@@ -830,8 +1648,10 @@ int network_add_ipv4ll_route(Network *network) {
         if (!network->ipv4ll_route)
                 return 0;
 
+        section_line = hashmap_find_free_section_line(network->routes_by_section);
+
         /* IPv4LLRoute= is in [Network] section. */
-        r = route_new_static(network, NULL, 0, &n);
+        r = route_new_static(network, network->filename, section_line, &n);
         if (r < 0)
                 return r;
 
@@ -853,6 +1673,7 @@ int network_add_ipv4ll_route(Network *network) {
 
 int network_add_default_route_on_device(Network *network) {
         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
+        unsigned section_line;
         int r;
 
         assert(network);
@@ -860,8 +1681,10 @@ int network_add_default_route_on_device(Network *network) {
         if (!network->default_route_on_device)
                 return 0;
 
+        section_line = hashmap_find_free_section_line(network->routes_by_section);
+
         /* DefaultRouteOnDevice= is in [Network] section. */
-        r = route_new_static(network, NULL, 0, &n);
+        r = route_new_static(network, network->filename, section_line, &n);
         if (r < 0)
                 return r;
 
@@ -874,113 +1697,6 @@ int network_add_default_route_on_device(Network *network) {
         return 0;
 }
 
-static const char * const route_type_table[__RTN_MAX] = {
-        [RTN_UNICAST]     = "unicast",
-        [RTN_LOCAL]       = "local",
-        [RTN_BROADCAST]   = "broadcast",
-        [RTN_ANYCAST]     = "anycast",
-        [RTN_MULTICAST]   = "multicast",
-        [RTN_BLACKHOLE]   = "blackhole",
-        [RTN_UNREACHABLE] = "unreachable",
-        [RTN_PROHIBIT]    = "prohibit",
-        [RTN_THROW]       = "throw",
-        [RTN_NAT]         = "nat",
-        [RTN_XRESOLVE]    = "xresolve",
-};
-
-assert_cc(__RTN_MAX <= UCHAR_MAX);
-DEFINE_STRING_TABLE_LOOKUP(route_type, int);
-
-static const char * const route_scope_table[] = {
-        [RT_SCOPE_UNIVERSE] = "global",
-        [RT_SCOPE_SITE]     = "site",
-        [RT_SCOPE_LINK]     = "link",
-        [RT_SCOPE_HOST]     = "host",
-        [RT_SCOPE_NOWHERE]  = "nowhere",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
-
-const char *format_route_scope(int scope, char *buf, size_t size) {
-        const char *s;
-        char *p = buf;
-
-        s = route_scope_to_string(scope);
-        if (s)
-                strpcpy(&p, size, s);
-        else
-                strpcpyf(&p, size, "%d", scope);
-
-        return buf;
-}
-
-static const char * const route_table_table[] = {
-        [RT_TABLE_DEFAULT] = "default",
-        [RT_TABLE_MAIN]    = "main",
-        [RT_TABLE_LOCAL]   = "local",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
-
-const char *format_route_table(int table, char *buf, size_t size) {
-        const char *s;
-        char *p = buf;
-
-        s = route_table_to_string(table);
-        if (s)
-                strpcpy(&p, size, s);
-        else
-                strpcpyf(&p, size, "%d", table);
-
-        return buf;
-}
-
-static const char * const route_protocol_table[] = {
-        [RTPROT_KERNEL] = "kernel",
-        [RTPROT_BOOT]   = "boot",
-        [RTPROT_STATIC] = "static",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
-
-static const char * const route_protocol_full_table[] = {
-        [RTPROT_REDIRECT] = "redirect",
-        [RTPROT_KERNEL]   = "kernel",
-        [RTPROT_BOOT]     = "boot",
-        [RTPROT_STATIC]   = "static",
-        [RTPROT_GATED]    = "gated",
-        [RTPROT_RA]       = "ra",
-        [RTPROT_MRT]      = "mrt",
-        [RTPROT_ZEBRA]    = "zebra",
-        [RTPROT_BIRD]     = "bird",
-        [RTPROT_DNROUTED] = "dnrouted",
-        [RTPROT_XORP]     = "xorp",
-        [RTPROT_NTK]      = "ntk",
-        [RTPROT_DHCP]     = "dhcp",
-        [RTPROT_MROUTED]  = "mrouted",
-        [RTPROT_BABEL]    = "babel",
-        [RTPROT_BGP]      = "bgp",
-        [RTPROT_ISIS]     = "isis",
-        [RTPROT_OSPF]     = "ospf",
-        [RTPROT_RIP]      = "rip",
-        [RTPROT_EIGRP]    = "eigrp",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
-
-const char *format_route_protocol(int protocol, char *buf, size_t size) {
-        const char *s;
-        char *p = buf;
-
-        s = route_protocol_full_to_string(protocol);
-        if (s)
-                strpcpy(&p, size, s);
-        else
-                strpcpyf(&p, size, "%d", protocol);
-
-        return buf;
-}
-
 int config_parse_gateway(
                 const char *unit,
                 const char *filename,
@@ -1004,9 +1720,8 @@ int config_parse_gateway(
         assert(data);
 
         if (streq(section, "Network")) {
-                /* we are not in an Route section, so treat
-                 * this as the special '0' section */
-                r = route_new_static(network, NULL, 0, &n);
+                /* we are not in an Route section, so use line number instead */
+                r = route_new_static(network, filename, line, &n);
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
@@ -1024,23 +1739,43 @@ int config_parse_gateway(
                         return 0;
                 }
 
+                if (isempty(rvalue)) {
+                        n->gateway_from_dhcp_or_ra = false;
+                        n->gw_family = AF_UNSPEC;
+                        n->gw = IN_ADDR_NULL;
+                        TAKE_PTR(n);
+                        return 0;
+                }
+
                 if (streq(rvalue, "_dhcp")) {
-                        n->gateway_from_dhcp = true;
+                        n->gateway_from_dhcp_or_ra = true;
+                        TAKE_PTR(n);
+                        return 0;
+                }
+
+                if (streq(rvalue, "_dhcp4")) {
+                        n->gw_family = AF_INET;
+                        n->gateway_from_dhcp_or_ra = true;
+                        TAKE_PTR(n);
+                        return 0;
+                }
+
+                if (streq(rvalue, "_ipv6ra")) {
+                        n->gw_family = AF_INET6;
+                        n->gateway_from_dhcp_or_ra = true;
                         TAKE_PTR(n);
                         return 0;
                 }
         }
 
-        if (n->family == AF_UNSPEC)
-                r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
-        else
-                r = in_addr_from_string(n->family, rvalue, &n->gw);
+        r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
+        n->gateway_from_dhcp_or_ra = false;
         TAKE_PTR(n);
         return 0;
 }
@@ -1184,6 +1919,7 @@ int config_parse_route_priority(
                 return 0;
         }
 
+        n->priority_set = true;
         TAKE_PTR(n);
         return 0;
 }
@@ -1368,6 +2104,7 @@ int config_parse_ipv6_route_preference(
                 return 0;
         }
 
+        n->pref_set = true;
         TAKE_PTR(n);
         return 0;
 }
@@ -1465,7 +2202,7 @@ int config_parse_tcp_window(
 
         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         Network *network = userdata;
-        uint64_t k;
+        uint32_t k;
         int r;
 
         assert(filename);
@@ -1483,13 +2220,13 @@ int config_parse_tcp_window(
                 return 0;
         }
 
-        r = parse_size(rvalue, 1024, &k);
+        r = safe_atou32(rvalue, &k);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
-        if (k > UINT32_MAX) {
+        if (k >= 1024) {
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
                 return 0;
@@ -1658,10 +2395,51 @@ int config_parse_multipath_route(
         return 0;
 }
 
-int route_section_verify(Route *route, Network *network) {
+static int route_section_verify(Route *route, Network *network) {
         if (section_is_invalid(route->section))
                 return -EINVAL;
 
+        if (route->gateway_from_dhcp_or_ra) {
+                if (route->gw_family == AF_UNSPEC) {
+                        /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
+                        switch (route->family) {
+                        case AF_UNSPEC:
+                                log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
+                                            "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
+                                            route->section->filename, route->section->line);
+                                route->family = AF_INET;
+                                break;
+                        case AF_INET:
+                        case AF_INET6:
+                                log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
+                                            "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
+                                            route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
+                                break;
+                        default:
+                                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                         "%s: Invalid route family. Ignoring [Route] section from line %u.",
+                                                         route->section->filename, route->section->line);
+                        }
+                        route->gw_family = route->family;
+                }
+
+                if (route->gw_family == AF_INET && !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
+                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
+                                                 "Ignoring [Route] section from line %u.",
+                                                 route->section->filename, route->section->line);
+
+                if (route->gw_family == AF_INET6 && !network->ipv6_accept_ra)
+                        return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
+                                                 "Ignoring [Route] section from line %u.",
+                                                 route->section->filename, route->section->line);
+        }
+
+        /* When only Gateway= is specified, assume the route family based on the Gateway address. */
+        if (route->family == AF_UNSPEC)
+                route->family = route->gw_family;
+
         if (route->family == AF_UNSPEC) {
                 assert(route->section);
 
@@ -1672,6 +2450,12 @@ int route_section_verify(Route *route, Network *network) {
                                          route->section->filename, route->section->line);
         }
 
+        if (route->family == AF_INET6 && route->gw_family == AF_INET)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: IPv4 gateway is configured for IPv6 route. "
+                                         "Ignoring [Route] section from line %u.",
+                                         route->section->filename, route->section->line);
+
         if (!route->table_set && network->vrf) {
                 route->table = VRF(network->vrf)->table;
                 route->table_set = true;
@@ -1687,8 +2471,16 @@ int route_section_verify(Route *route, Network *network) {
                         route->scope = RT_SCOPE_LINK;
         }
 
-        if (network->n_static_addresses == 0 &&
-            in_addr_is_null(route->family, &route->gw) == 0 &&
+        if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
+                log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
+                route->scope = RT_SCOPE_UNIVERSE;
+        }
+
+        if (route->family == AF_INET6 && route->priority == 0)
+                route->priority = IP6_RT_PRIO_USER;
+
+        if (ordered_hashmap_isempty(network->addresses_by_section) &&
+            in_addr_is_null(route->gw_family, &route->gw) == 0 &&
             route->gateway_onlink < 0) {
                 log_warning("%s: Gateway= without static address configured. "
                             "Enabling GatewayOnLink= option.",
@@ -1698,3 +2490,13 @@ int route_section_verify(Route *route, Network *network) {
 
         return 0;
 }
+
+void network_drop_invalid_routes(Network *network) {
+        Route *route;
+
+        assert(network);
+
+        HASHMAP_FOREACH(route, network->routes_by_section)
+                if (route_section_verify(route, network) < 0)
+                        route_free(route);
+}
index 75651fa51228d19376e85d838657122856059d67..e896719e13b794526b6cad099aab5a82069607d8 100644 (file)
@@ -1,33 +1,30 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "conf-parser.h"
-#include "macro.h"
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
 
-typedef struct Route Route;
-typedef struct NetworkConfigSection NetworkConfigSection;
+#include "sd-netlink.h"
 
-#include "networkd-network.h"
+#include "conf-parser.h"
+#include "in-addr-util.h"
+#include "networkd-link.h"
 #include "networkd-util.h"
 
-typedef struct MultipathRouteVia {
-        uint16_t family;
-        union in_addr_union address;
-} _packed_ MultipathRouteVia;
-
-typedef struct MultipathRoute {
-        MultipathRouteVia gateway;
-        int ifindex;
-        uint32_t weight;
-} MultipathRoute;
+typedef struct Manager Manager;
+typedef struct Network Network;
 
-struct Route {
+typedef struct Route {
         Network *network;
         NetworkConfigSection *section;
 
         Link *link;
+        Manager *manager;
 
         int family;
+        int gw_family;
+        uint32_t gw_weight;
         int quickack;
         int fast_open_no_cookie;
         int ttl_propagate;
@@ -35,20 +32,24 @@ struct Route {
         unsigned char dst_prefixlen;
         unsigned char src_prefixlen;
         unsigned char scope;
-        bool scope_set;
         unsigned char protocol;  /* RTPROT_* */
         unsigned char type; /* RTN_* */
         unsigned char tos;
         uint32_t priority; /* note that ip(8) calls this 'metric' */
         uint32_t table;
-        bool table_set;
         uint32_t mtu;
         uint32_t initcwnd;
         uint32_t initrwnd;
         unsigned char pref;
         unsigned flags;
         int gateway_onlink;
-        bool gateway_from_dhcp;
+
+        bool scope_set:1;
+        bool table_set:1;
+        bool priority_set:1;
+        bool protocol_set:1;
+        bool pref_set:1;
+        bool gateway_from_dhcp_or_ra:1;
 
         union in_addr_union gw;
         union in_addr_union dst;
@@ -58,43 +59,33 @@ struct Route {
 
         usec_t lifetime;
         sd_event_source *expire;
-
-        LIST_FIELDS(Route, routes);
-};
+} Route;
 
 void route_hash_func(const Route *route, struct siphash *state);
 int route_compare_func(const Route *a, const Route *b);
 extern const struct hash_ops route_hash_ops;
 
 int route_new(Route **ret);
-void route_free(Route *route);
-int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
-int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
-
-int route_get(Link *link, Route *in, Route **ret);
-int route_add(Link *link, Route *in, Route **ret);
-int route_add_foreign(Link *link, Route *in, Route **ret);
-bool route_equal(Route *r1, Route *r2);
-
-int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
-int route_section_verify(Route *route, Network *network);
-
+Route *route_free(Route *route);
 DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
 
-int network_add_ipv4ll_route(Network *network);
-int network_add_default_route_on_device(Network *network);
+int route_configure(const Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
+int route_remove(const Route *route, Manager *manager, Link *link, link_netlink_message_handler_t callback);
 
-const char* route_type_to_string(int t) _const_;
-int route_type_from_string(const char *s) _pure_;
+int link_set_routes(Link *link);
+int link_drop_routes(Link *link);
+int link_drop_foreign_routes(Link *link);
+int link_serialize_routes(const Link *link, FILE *f);
+int link_deserialize_routes(Link *link, const char *routes);
 
-#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
-const char *format_route_scope(int scope, char *buf, size_t size);
+uint32_t link_get_dhcp_route_table(const Link *link);
+uint32_t link_get_ipv6_accept_ra_route_table(const Link *link);
 
-#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
-const char *format_route_table(int table, char *buf, size_t size);
+int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
 
-#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
-const char *format_route_protocol(int protocol, char *buf, size_t size);
+int network_add_ipv4ll_route(Network *network);
+int network_add_default_route_on_device(Network *network);
+void network_drop_invalid_routes(Network *network);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
 CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
index 3b95ea76b09f813e187683f3ddb5d7a4a32fa212..de60bd9555cdf9b2ea5af810904cc4eaa081146f 100644 (file)
@@ -9,9 +9,9 @@
 #include "fileio.h"
 #include "format-util.h"
 #include "ip-protocol-list.h"
-#include "networkd-routing-policy-rule.h"
 #include "netlink-util.h"
 #include "networkd-manager.h"
+#include "networkd-routing-policy-rule.h"
 #include "networkd-util.h"
 #include "parse-util.h"
 #include "socket-util.h"
 #include "strv.h"
 #include "user-util.h"
 
-int routing_policy_rule_new(RoutingPolicyRule **ret) {
+RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
+        if (!rule)
+                return NULL;
+
+        if (rule->network) {
+                assert(rule->section);
+                hashmap_remove(rule->network->rules_by_section, rule->section);
+        }
+
+        if (rule->manager) {
+                if (set_get(rule->manager->rules, rule) == rule)
+                        set_remove(rule->manager->rules, rule);
+                if (set_get(rule->manager->rules_foreign, rule) == rule)
+                        set_remove(rule->manager->rules_foreign, rule);
+        }
+
+        network_config_section_free(rule->section);
+        free(rule->iif);
+        free(rule->oif);
+
+        return mfree(rule);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
+
+static int routing_policy_rule_new(RoutingPolicyRule **ret) {
         RoutingPolicyRule *rule;
 
         rule = new(RoutingPolicyRule, 1);
@@ -37,31 +62,43 @@ int routing_policy_rule_new(RoutingPolicyRule **ret) {
         return 0;
 }
 
-void routing_policy_rule_free(RoutingPolicyRule *rule) {
+static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
+        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        int r;
 
-        if (!rule)
-                return;
+        assert(network);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
 
-        if (rule->network) {
-                LIST_REMOVE(rules, rule->network->rules, rule);
-                assert(rule->network->n_rules > 0);
-                rule->network->n_rules--;
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-                if (rule->section)
-                        hashmap_remove(rule->network->rules_by_section, rule->section);
+        rule = hashmap_get(network->rules_by_section, n);
+        if (rule) {
+                *ret = TAKE_PTR(rule);
+                return 0;
         }
 
-        if (rule->manager) {
-                if (set_get(rule->manager->rules, rule) == rule)
-                        set_remove(rule->manager->rules, rule);
-                if (set_get(rule->manager->rules_foreign, rule) == rule)
-                        set_remove(rule->manager->rules_foreign, rule);
-        }
+        r = routing_policy_rule_new(&rule);
+        if (r < 0)
+                return r;
 
-        network_config_section_free(rule->section);
-        free(rule->iif);
-        free(rule->oif);
-        free(rule);
+        rule->network = network;
+        rule->section = TAKE_PTR(n);
+
+        r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(network->rules_by_section, rule->section, rule);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(rule);
+        return 0;
 }
 
 static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
@@ -234,7 +271,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 routing_policy_rule_compare_func,
                 routing_policy_rule_free);
 
-int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
+static int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
 
         RoutingPolicyRule *existing;
 
@@ -257,31 +294,15 @@ int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRu
         return -ENOENT;
 }
 
-int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
-        int r;
-
-        assert(m);
-
-        if (set_contains(m->rules_foreign, rule)) {
-                set_remove(m->rules_foreign, rule);
-
-                r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        routing_policy_rule_free(rule);
-        }
-
-        return -ENOENT;
-}
-
-static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
+static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
         int r;
 
         assert(m);
         assert(rules);
         assert(in);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(in->family == AF_UNSPEC || in->family == family);
 
         r = routing_policy_rule_new(&rule);
         if (r < 0)
@@ -293,6 +314,8 @@ static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPoli
         if (r < 0)
                 return r;
 
+        rule->family = family;
+
         r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
         if (r < 0)
                 return r;
@@ -306,12 +329,122 @@ static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPoli
         return 0;
 }
 
-static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
-        return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
+static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, int family, RoutingPolicyRule **ret) {
+        return routing_policy_rule_add_internal(m, &m->rules, rule, family, ret);
 }
 
-int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
-        return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
+static int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
+        return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, rule->family, ret);
+}
+
+static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(rule);
+        assert(m);
+        assert(link);
+
+        if (in_addr_is_null(rule->family, &rule->from) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
+
+                r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set source prefix length: %m");
+        }
+
+        if (in_addr_is_null(rule->family, &rule->to) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
+
+                r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
+        }
+
+        r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
+
+        if (rule->tos > 0) {
+                r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set IP rule TOS: %m");
+        }
+
+        if (rule->table < 256) {
+                r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set IP rule table: %m");
+        } else {
+                r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set IP rule table: %m");
+
+                r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
+        }
+
+        if (rule->fwmark > 0) {
+                r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
+
+                r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
+        }
+
+        if (rule->iif) {
+                r = sd_netlink_message_append_string(m, FRA_IIFNAME, rule->iif);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_IIFNAME attribute: %m");
+        }
+
+        if (rule->oif) {
+                r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
+        }
+
+        r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
+
+        if (rule->sport.start != 0 || rule->sport.end != 0) {
+                r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
+        }
+
+        if (rule->dport.start != 0 || rule->dport.end != 0) {
+                r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
+        }
+
+        if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
+                r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_UID_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_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
+        }
+
+        if (rule->suppress_prefixlen >= 0) {
+                r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
+        }
+
+        return 0;
 }
 
 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@@ -333,7 +466,7 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
         return 1;
 }
 
-int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
+static int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
@@ -359,28 +492,12 @@ int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m");
 
-        if (in_addr_is_null(rule->family, &rule->from) == 0) {
-                r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
-
-                r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set source prefix length: %m");
-        }
-
-        if (in_addr_is_null(rule->family, &rule->to) == 0) {
-                r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
-
-                r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
-        }
+        r = routing_policy_rule_set_netlink_message(rule, m, link);
+        if (r < 0)
+                return r;
 
         r = netlink_call_async(link->manager->rtnl, NULL, m,
-                               callback ?: routing_policy_rule_remove_handler,
+                               routing_policy_rule_remove_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -390,53 +507,6 @@ int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink
         return 0;
 }
 
-static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
-        _cleanup_(network_config_section_freep) NetworkConfigSection *n = 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;
-
-                rule = hashmap_get(network->rules_by_section, n);
-                if (rule) {
-                        *ret = TAKE_PTR(rule);
-
-                        return 0;
-                }
-        }
-
-        r = routing_policy_rule_new(&rule);
-        if (r < 0)
-                return r;
-
-        rule->network = network;
-        LIST_APPEND(rules, network->rules, rule);
-        network->n_rules++;
-
-        if (filename) {
-                rule->section = TAKE_PTR(n);
-
-                r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
-                if (r < 0)
-                        return r;
-
-                r = hashmap_put(network->rules_by_section, rule->section, rule);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = TAKE_PTR(rule);
-
-        return 0;
-}
-
 static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -467,7 +537,7 @@ static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m,
         return 1;
 }
 
-int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
+static int routing_policy_rule_configure_internal(RoutingPolicyRule *rule, int family, Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
@@ -480,177 +550,380 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *from = NULL, *to = NULL;
 
-                (void) in_addr_to_string(rule->family, &rule->from, &from);
-                (void) in_addr_to_string(rule->family, &rule->to, &to);
+                (void) in_addr_to_string(family, &rule->from, &from);
+                (void) in_addr_to_string(family, &rule->to, &to);
 
                 log_link_debug(link,
                                "Configuring routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
                                rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
         }
 
-        r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
+        r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, family);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
 
-        if (in_addr_is_null(rule->family, &rule->from) == 0) {
-                r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
+        r = routing_policy_rule_set_netlink_message(rule, m, link);
+        if (r < 0)
+                return r;
+
+        r = netlink_call_async(link->manager->rtnl, NULL, m,
+                               routing_policy_rule_handler,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+        link_ref(link);
+        link->routing_policy_rule_messages++;
+
+        r = routing_policy_rule_add(link->manager, rule, family, NULL);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not add rule: %m");
+
+        return 1;
+}
+
+static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) {
+        int r;
+
+        if (IN_SET(rule->family, AF_INET, AF_INET6))
+                return routing_policy_rule_configure_internal(rule, rule->family, link);
+
+        if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
+                r = routing_policy_rule_configure_internal(rule, AF_INET, link);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
+                        return r;
+        }
+
+        if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
+                r = routing_policy_rule_configure_internal(rule, AF_INET6, link);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
+        Link *link;
+
+        assert(m);
+        assert(rule);
+
+        HASHMAP_FOREACH(link, m->links) {
+                RoutingPolicyRule *link_rule;
+
+                if (!link->network)
+                        continue;
+
+                HASHMAP_FOREACH(link_rule, link->network->rules_by_section)
+                        if (routing_policy_rule_compare_func(link_rule, rule) == 0)
+                                return true;
+        }
+
+        return false;
+}
+
+static void routing_policy_rule_purge(Manager *m, Link *link) {
+        RoutingPolicyRule *rule;
+        int r;
+
+        assert(m);
+        assert(link);
+
+        SET_FOREACH(rule, m->rules_saved) {
+                RoutingPolicyRule *existing;
+
+                existing = set_get(m->rules_foreign, rule);
+                if (!existing)
+                        continue; /* Saved rule does not exist anymore. */
+
+                if (manager_links_have_routing_policy_rule(m, existing))
+                        continue; /* Existing links have the saved rule. */
+
+                /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
+                 * later when it is requested. */
+
+                r = routing_policy_rule_remove(existing, link);
+                if (r < 0) {
+                        log_warning_errno(r, "Could not remove routing policy rules: %m");
+                        continue;
+                }
+
+                link->routing_policy_rule_remove_messages++;
+
+                assert_se(set_remove(m->rules_foreign, existing) == existing);
+                routing_policy_rule_free(existing);
+        }
+}
+
+int link_set_routing_policy_rules(Link *link) {
+        RoutingPolicyRule *rule;
+        int r;
+
+        assert(link);
+        assert(link->network);
+
+        link->routing_policy_rules_configured = false;
+
+        HASHMAP_FOREACH(rule, link->network->rules_by_section) {
+                RoutingPolicyRule *existing;
+
+                r = routing_policy_rule_get(link->manager, rule, &existing);
+                if (r > 0)
+                        continue;
+                if (r == 0) {
+                        r = set_ensure_put(&link->manager->rules, &routing_policy_rule_hash_ops, existing);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not store existing routing policy rule: %m");
+
+                        set_remove(link->manager->rules_foreign, existing);
+                        continue;
+                }
 
-                r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
+                r = routing_policy_rule_configure(rule, link);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set source prefix length: %m");
+                        return log_link_warning_errno(link, r, "Could not set routing policy rule: %m");
         }
 
-        if (in_addr_is_null(rule->family, &rule->to) == 0) {
-                r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
-
-                r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
+        routing_policy_rule_purge(link->manager, link);
+        if (link->routing_policy_rule_messages == 0)
+                link->routing_policy_rules_configured = true;
+        else {
+                log_link_debug(link, "Setting routing policy rules");
+                link_set_state(link, LINK_STATE_CONFIGURING);
         }
 
-        r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
+        return 0;
+}
 
-        if (rule->tos > 0) {
-                r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set IP rule TOS: %m");
-        }
+int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
+        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+        _cleanup_free_ char *from = NULL, *to = NULL;
+        RoutingPolicyRule *rule = NULL;
+        const char *iif = NULL, *oif = NULL;
+        uint32_t suppress_prefixlen;
+        unsigned flags;
+        uint16_t type;
+        int r;
 
-        if (rule->table < 256) {
-                r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set IP rule table: %m");
-        } else {
-                r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not set IP rule table: %m");
+        assert(rtnl);
+        assert(message);
 
-                r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
-        }
+                        log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
 
-        if (rule->fwmark > 0) {
-                r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
+                return 0;
+        }
 
-                r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
+                log_warning("rtnl: received unexpected message type %u when processing rule, ignoring.", type);
+                return 0;
         }
 
-        if (rule->iif) {
-                r = sd_netlink_message_append_string(m, FRA_IIFNAME, rule->iif);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_IIFNAME attribute: %m");
+        r = routing_policy_rule_new(&tmp);
+        if (r < 0) {
+                log_oom();
+                return 0;
         }
 
-        if (rule->oif) {
-                r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
+        r = sd_rtnl_message_get_family(message, &tmp->family);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
+                return 0;
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_debug("rtnl: received rule message with invalid family %d, ignoring.", tmp->family);
+                return 0;
         }
 
-        r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
+        switch (tmp->family) {
+        case AF_INET:
+                r = sd_netlink_message_read_in_addr(message, FRA_SRC, &tmp->from.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
+                        if (r < 0) {
+                                log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
+                                return 0;
+                        }
+                }
 
-        if (rule->sport.start != 0 || rule->sport.end != 0) {
-                r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
-        }
+                r = sd_netlink_message_read_in_addr(message, FRA_DST, &tmp->to.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
+                        if (r < 0) {
+                                log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
+                                return 0;
+                        }
+                }
 
-        if (rule->dport.start != 0 || rule->dport.end != 0) {
-                r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
+                break;
+
+        case AF_INET6:
+                r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &tmp->from.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
+                        if (r < 0) {
+                                log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
+                                return 0;
+                        }
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, FRA_DST, &tmp->to.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
+                        if (r < 0) {
+                                log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
+                                return 0;
+                        }
+                }
+
+                break;
+
+        default:
+                assert_not_reached("Received rule message with unsupported address family");
         }
 
-        if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
-                r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_UID_RANGE attribute: %m");
+        r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
+                return 0;
         }
+        tmp->invert_rule = flags & FIB_RULE_INVERT;
 
-        if (rule->invert_rule) {
-                r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
+        r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
+                return 0;
         }
 
-        if (rule->suppress_prefixlen >= 0) {
-                r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
+        r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
+                return 0;
         }
 
-        rule->link = link;
+        r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
+                return 0;
+        }
 
-        r = netlink_call_async(link->manager->rtnl, NULL, m,
-                               callback ?: routing_policy_rule_handler,
-                               link_netlink_destroy_callback, link);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+        r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
+                return 0;
+        }
 
-        link_ref(link);
+        r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
+                return 0;
+        }
 
-        r = routing_policy_rule_add(link->manager, rule, NULL);
+        r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
+                return 0;
+        }
+        r = free_and_strdup(&tmp->iif, iif);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not add rule: %m");
-
-        return 1;
-}
-
-int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
-        int r;
-
-        if (section_is_invalid(rule->section))
-                return -EINVAL;
+                return log_oom();
 
-        if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
-            (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                "%s: address family specified by Family= conflicts with the address "
-                                "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
-                                rule->section->filename, rule->section->line);
+        r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
+                return 0;
+        }
+        r = free_and_strdup(&tmp->oif, oif);
+        if (r < 0)
+                return log_oom();
 
-        if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
-                _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
+        r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
+                return 0;
+        }
 
-                assert(rule->family == AF_UNSPEC);
+        r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
+                return 0;
+        }
 
-                /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
+        r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
+                return 0;
+        }
 
-                r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
-                if (r < 0)
-                        return r;
+        r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
+                return 0;
+        }
 
-                r = routing_policy_rule_copy(rule6, rule);
-                if (r < 0)
-                        return r;
+        r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_PREFIXLEN, &suppress_prefixlen);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_PREFIXLEN attribute, ignoring: %m");
+                return 0;
+        }
+        if (r >= 0)
+                tmp->suppress_prefixlen = (int) suppress_prefixlen;
 
-                rule->family = AF_INET;
-                rule6->family = AF_INET6;
+        (void) routing_policy_rule_get(m, tmp, &rule);
 
-                TAKE_PTR(rule6);
+        if (DEBUG_LOGGING) {
+                (void) in_addr_to_string(tmp->family, &tmp->from, &from);
+                (void) in_addr_to_string(tmp->family, &tmp->to, &to);
         }
 
-        if (rule->family == AF_UNSPEC) {
-                if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
-                        rule->family = AF_INET6;
-                else
-                        rule->family = AF_INET;
+        switch (type) {
+        case RTM_NEWRULE:
+                if (rule)
+                        log_debug("Received remembered routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
+                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
+                else {
+                        log_debug("Remembering foreign routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
+                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
+                        r = routing_policy_rule_add_foreign(m, tmp, &rule);
+                        if (r < 0) {
+                                log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
+                                return 0;
+                        }
+                }
+                break;
+        case RTM_DELRULE:
+                if (rule) {
+                        log_debug("Forgetting routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
+                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
+                        routing_policy_rule_free(rule);
+                } else
+                        log_debug("Kernel removed a routing policy rule we don't remember: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32", ignoring.",
+                                  tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
+                break;
+
+        default:
+                assert_not_reached("Received invalid RTNL message type");
         }
 
-        return 0;
+        return 1;
 }
 
 static int parse_fwmark_fwmask(const char *s, uint32_t *ret_fwmark, uint32_t *ret_fwmask) {
@@ -1183,14 +1456,40 @@ int config_parse_routing_policy_rule_suppress_prefixlen(
         return 0;
 }
 
+static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
+        if (section_is_invalid(rule->section))
+                return -EINVAL;
+
+        if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
+            (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                "%s: address family specified by Family= conflicts with the address "
+                                "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
+                                rule->section->filename, rule->section->line);
+
+        if (rule->family == AF_UNSPEC && rule->address_family == ADDRESS_FAMILY_NO)
+                rule->family = AF_INET;
+
+        return 0;
+}
+
+void network_drop_invalid_routing_policy_rules(Network *network) {
+        RoutingPolicyRule *rule;
+
+        assert(network);
+
+        HASHMAP_FOREACH(rule, network->rules_by_section)
+                if (routing_policy_rule_section_verify(rule) < 0)
+                        routing_policy_rule_free(rule);
+}
+
 int routing_policy_serialize_rules(Set *rules, FILE *f) {
-        RoutingPolicyRule *rule = NULL;
+        RoutingPolicyRule *rule;
         int r;
 
         assert(f);
 
         SET_FOREACH(rule, rules) {
-                _cleanup_free_ char *from_str = NULL, *to_str = NULL;
                 const char *family_str;
                 bool space = false;
 
@@ -1204,24 +1503,28 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
                 }
 
                 if (!in_addr_is_null(rule->family, &rule->from)) {
-                        r = in_addr_to_string(rule->family, &rule->from, &from_str);
+                        _cleanup_free_ char *str = NULL;
+
+                        r = in_addr_to_string(rule->family, &rule->from, &str);
                         if (r < 0)
                                 return r;
 
                         fprintf(f, "%sfrom=%s/%hhu",
                                 space ? " " : "",
-                                from_str, rule->from_prefixlen);
+                                str, rule->from_prefixlen);
                         space = true;
                 }
 
                 if (!in_addr_is_null(rule->family, &rule->to)) {
-                        r = in_addr_to_string(rule->family, &rule->to, &to_str);
+                        _cleanup_free_ char *str = NULL;
+
+                        r = in_addr_to_string(rule->family, &rule->to, &str);
                         if (r < 0)
                                 return r;
 
                         fprintf(f, "%sto=%s/%hhu",
                                 space ? " " : "",
-                                to_str, rule->to_prefixlen);
+                                str, rule->to_prefixlen);
                         space = true;
                 }
 
@@ -1307,31 +1610,31 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
         return 0;
 }
 
-static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
+static int routing_policy_rule_read_full_file(const char *state_file, char ***ret) {
+        _cleanup_strv_free_ char **lines = NULL;
         _cleanup_free_ char *s = NULL;
-        size_t size;
         int r;
 
         assert(state_file);
 
-        r = read_full_file(state_file, &s, &size);
-        if (r == -ENOENT)
-                return -ENODATA;
+        r = read_full_file(state_file, &s, NULL);
+        if (r == -ENOENT) {
+                *ret = NULL;
+                return 0;
+        }
         if (r < 0)
                 return r;
-        if (size <= 0)
-                return -ENODATA;
 
-        *ret = TAKE_PTR(s);
+        lines = strv_split_newlines(s);
+        if (!lines)
+                return -ENOMEM;
 
-        return size;
+        *ret = TAKE_PTR(lines);
+        return 0;
 }
 
 int routing_policy_load_rules(const char *state_file, Set **rules) {
-        _cleanup_strv_free_ char **l = NULL;
-        _cleanup_free_ char *data = NULL;
-        uint16_t low = 0, high = 0;
-        const char *p;
+        _cleanup_strv_free_ char **data = NULL;
         char **i;
         int r;
 
@@ -1339,15 +1642,12 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
         assert(rules);
 
         r = routing_policy_rule_read_full_file(state_file, &data);
-        if (r <= 0)
-                return r;
-
-        l = strv_split_newlines(data);
-        if (!l)
-                return -ENOMEM;
+        if (r < 0)
+                return log_warning_errno(r, "Failed to read %s, ignoring: %m", state_file);
 
-        STRV_FOREACH(i, l) {
+        STRV_FOREACH(i, data) {
                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
+                const char *p;
 
                 p = startswith(*i, "RULE=");
                 if (!p)
@@ -1355,7 +1655,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                 r = routing_policy_rule_new(&rule);
                 if (r < 0)
-                        return r;
+                        return log_oom();
 
                 for (;;) {
                         _cleanup_free_ char *a = NULL;
@@ -1363,7 +1663,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                         r = extract_first_word(&p, &a, NULL, 0);
                         if (r < 0)
-                                return r;
+                                return log_oom();
                         if (r == 0)
                                 break;
 
@@ -1385,7 +1685,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
                                         continue;
                                 }
                                 rule->family = r;
-                        } if (STR_IN_SET(a, "from", "to")) {
+                        } else if (STR_IN_SET(a, "from", "to")) {
                                 union in_addr_union *buffer;
                                 uint8_t *prefixlen;
 
@@ -1444,6 +1744,8 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
                                         continue;
                                 }
                         } else if (streq(a, "sourceport")) {
+                                uint16_t low, high;
+
                                 r = parse_ip_port_range(b, &low, &high);
                                 if (r < 0) {
                                         log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
@@ -1453,6 +1755,8 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
                                 rule->sport.start = low;
                                 rule->sport.end = high;
                         } else if (streq(a, "destinationport")) {
+                                uint16_t low, high;
+
                                 r = parse_ip_port_range(b, &low, &high);
                                 if (r < 0) {
                                         log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
@@ -1495,7 +1799,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                 r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
                 if (r < 0) {
-                        log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
+                        log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", *i);
                         continue;
                 }
                 if (r > 0)
@@ -1504,53 +1808,3 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
         return 0;
 }
-
-static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
-        RoutingPolicyRule *link_rule;
-        Link *link;
-
-        assert(m);
-        assert(rule);
-
-        HASHMAP_FOREACH(link, m->links) {
-                if (!link->network)
-                        continue;
-
-                LIST_FOREACH(rules, link_rule, link->network->rules)
-                        if (routing_policy_rule_compare_func(link_rule, rule) == 0)
-                                return true;
-        }
-
-        return false;
-}
-
-void routing_policy_rule_purge(Manager *m, Link *link) {
-        RoutingPolicyRule *rule, *existing;
-        int r;
-
-        assert(m);
-        assert(link);
-
-        SET_FOREACH(rule, m->rules_saved) {
-                existing = set_get(m->rules_foreign, rule);
-                if (!existing)
-                        continue; /* Saved rule does not exist anymore. */
-
-                if (manager_links_have_routing_policy_rule(m, existing))
-                        continue; /* Existing links have the saved rule. */
-
-                /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
-                 * later when it is requested. */
-
-                r = routing_policy_rule_remove(existing, link, NULL);
-                if (r < 0) {
-                        log_warning_errno(r, "Could not remove routing policy rules: %m");
-                        continue;
-                }
-
-                link->routing_policy_rule_remove_messages++;
-
-                assert_se(set_remove(m->rules_foreign, existing) == existing);
-                routing_policy_rule_free(existing);
-        }
-}
index af954e8fb5d3bc94627021045f0fc75ef172a90e..bc1193a111171a8c2e7478209eb1b7fadcbe9cf0 100644 (file)
@@ -2,28 +2,22 @@
 #pragma once
 
 #include <inttypes.h>
-#include <netinet/in.h>
 #include <linux/fib_rules.h>
 #include <stdbool.h>
+#include <stdio.h>
 
-#include "in-addr-util.h"
 #include "conf-parser.h"
-
-typedef struct RoutingPolicyRule RoutingPolicyRule;
-
-#include "networkd-link.h"
-#include "networkd-network.h"
+#include "in-addr-util.h"
 #include "networkd-util.h"
+#include "set.h"
 
 typedef struct Network Network;
 typedef struct Link Link;
-typedef struct NetworkConfigSection NetworkConfigSection;
 typedef struct Manager Manager;
 
-struct RoutingPolicyRule {
+typedef struct RoutingPolicyRule {
         Manager *manager;
         Network *network;
-        Link *link;
         NetworkConfigSection *section;
 
         bool invert_rule;
@@ -52,25 +46,18 @@ struct RoutingPolicyRule {
         struct fib_rule_uid_range uid_range;
 
         int suppress_prefixlen;
+} RoutingPolicyRule;
 
-        LIST_FIELDS(RoutingPolicyRule, rules);
-};
+RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule);
 
-int routing_policy_rule_new(RoutingPolicyRule **ret);
-void routing_policy_rule_free(RoutingPolicyRule *rule);
+void network_drop_invalid_routing_policy_rules(Network *network);
 
-DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
-int routing_policy_rule_section_verify(RoutingPolicyRule *rule);
+int link_set_routing_policy_rules(Link *link);
 
-int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
-int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
+int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
 
-int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
-int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
-int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule);
 int routing_policy_serialize_rules(Set *rules, FILE *f);
 int routing_policy_load_rules(const char *state_file, Set **rules);
-void routing_policy_rule_purge(Manager *m, Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);
index 7d99707343400fbcdc8371e46c0f3f5eff367cd2..61382a89937cc199409110d1c17be39e9b1ff662 100644 (file)
@@ -108,7 +108,7 @@ static int sr_iov_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         return 1;
 }
 
-int sr_iov_configure(Link *link, SRIOV *sr_iov) {
+static int sr_iov_configure(Link *link, SRIOV *sr_iov) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -226,7 +226,28 @@ int sr_iov_configure(Link *link, SRIOV *sr_iov) {
         return 0;
 }
 
-int sr_iov_section_verify(SRIOV *sr_iov) {
+int link_configure_sr_iov(Link *link) {
+        SRIOV *sr_iov;
+        int r;
+
+        link->sr_iov_configured = false;
+        link->sr_iov_messages = 0;
+
+        ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
+                r = sr_iov_configure(link, sr_iov);
+                if (r < 0)
+                        return r;
+        }
+
+        if (link->sr_iov_messages == 0)
+                link->sr_iov_configured = true;
+        else
+                log_link_debug(link, "Configuring SR-IOV");
+
+        return 0;
+}
+
+static int sr_iov_section_verify(SRIOV *sr_iov) {
         assert(sr_iov);
 
         if (section_is_invalid(sr_iov->section))
@@ -241,6 +262,16 @@ int sr_iov_section_verify(SRIOV *sr_iov) {
         return 0;
 }
 
+void network_drop_invalid_sr_iov(Network *network) {
+        SRIOV *sr_iov;
+
+        assert(network);
+
+        ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
+                if (sr_iov_section_verify(sr_iov) < 0)
+                        sr_iov_free(sr_iov);
+}
+
 int config_parse_sr_iov_uint32(
                 const char *unit,
                 const char *filename,
index a545d1292ae0e5aec540964609a5ead866bf48c6..8a48545d64b8019c78ad89930ad6814476f07325 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/if_link.h>
 
 #include "conf-parser.h"
+#include "ether-addr-util.h"
 #include "networkd-link.h"
 #include "networkd-network.h"
 #include "networkd-util.h"
@@ -33,9 +34,8 @@ typedef struct SRIOV {
 } SRIOV;
 
 SRIOV *sr_iov_free(SRIOV *sr_iov);
-
-int sr_iov_configure(Link *link, SRIOV *sr_iov);
-int sr_iov_section_verify(SRIOV *sr_iov);
+int link_configure_sr_iov(Link *link);
+void network_drop_invalid_sr_iov(Network *network);
 
 DEFINE_NETWORK_SECTION_FUNCTIONS(SRIOV, sr_iov_free);
 
diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c
new file mode 100644 (file)
index 0000000..de4ed95
--- /dev/null
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <netinet/in.h>
+#include <linux/if.h>
+
+#include "missing_network.h"
+#include "networkd-link.h"
+#include "networkd-network.h"
+#include "networkd-sysctl.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "sysctl-util.h"
+
+static int link_update_ipv6_sysctl(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link_ipv6_enabled(link))
+                return 0;
+
+        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
+}
+
+static int link_set_proxy_arp(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        if (link->network->proxy_arp < 0)
+                return 0;
+
+        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
+}
+
+static bool link_ip_forward_enabled(Link *link, int family) {
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+
+        if (family == AF_INET6 && !socket_ipv6_is_supported())
+                return false;
+
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        return link->network->ip_forward & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
+}
+
+static int link_set_ipv4_forward(Link *link) {
+        assert(link);
+
+        if (!link_ip_forward_enabled(link, AF_INET))
+                return 0;
+
+        /* We propagate the forwarding flag from one interface to the
+         * global setting one way. This means: as long as at least one
+         * interface was configured at any time that had IP forwarding
+         * enabled the setting will stay on for good. We do this
+         * primarily to keep IPv4 and IPv6 packet forwarding behaviour
+         * somewhat in sync (see below). */
+
+        return sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
+}
+
+static int link_set_ipv6_forward(Link *link) {
+        assert(link);
+
+        if (!link_ip_forward_enabled(link, AF_INET6))
+                return 0;
+
+        /* On Linux, the IPv6 stack does not know a per-interface
+         * packet forwarding setting: either packet forwarding is on
+         * for all, or off for all. We hence don't bother with a
+         * per-interface setting, but simply propagate the interface
+         * flag, if it is set, to the global flag, one-way. Note that
+         * while IPv4 would allow a per-interface flag, we expose the
+         * same behaviour there and also propagate the setting from
+         * one to all, to keep things simple (see above). */
+
+        return sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
+}
+
+static int link_set_ipv6_privacy_extensions(Link *link) {
+        assert(link);
+
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) link->network->ipv6_privacy_extensions);
+}
+
+static int link_set_ipv6_accept_ra(Link *link) {
+        assert(link);
+
+        /* Make this a NOP if IPv6 is not available */
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
+}
+
+static int link_set_ipv6_dad_transmits(Link *link) {
+        assert(link);
+
+        /* Make this a NOP if IPv6 is not available */
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        if (link->network->ipv6_dad_transmits < 0)
+                return 0;
+
+        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
+}
+
+static int link_set_ipv6_hop_limit(Link *link) {
+        assert(link);
+
+        /* Make this a NOP if IPv6 is not available */
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        if (link->network->ipv6_hop_limit < 0)
+                return 0;
+
+        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
+}
+
+static int link_set_ipv4_accept_local(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (link->network->ipv4_accept_local < 0)
+                return 0;
+
+        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0);
+}
+
+int link_set_sysctl(Link *link) {
+        int r;
+
+        assert(link);
+
+        /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
+         * for this interface, then enable IPv6 */
+        r = link_update_ipv6_sysctl(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
+
+        r = link_set_proxy_arp(link);
+        if (r < 0)
+               log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
+
+        r = link_set_ipv4_forward(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
+
+        r = link_set_ipv6_forward(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");;
+
+        r = link_set_ipv6_privacy_extensions(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface, ignorign: %m");
+
+        r = link_set_ipv6_accept_ra(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
+
+        r = link_set_ipv6_dad_transmits(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
+
+        r = link_set_ipv6_hop_limit(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
+
+        r = link_set_ipv4_accept_local(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
+
+        return 0;
+}
+
+int link_set_ipv6_mtu(Link *link) {
+        int r;
+
+        assert(link);
+
+        /* Make this a NOP if IPv6 is not available */
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (link->network->ipv6_mtu == 0)
+                return 0;
+
+        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
+        if (r < 0)
+                return r;
+
+        link->ipv6_mtu_set = true;
+
+        return 0;
+}
+
+static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
+        [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
+        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
+        [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
+                                        IPV6_PRIVACY_EXTENSIONS_YES);
+
+int config_parse_ipv6_privacy_extensions(
+                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) {
+
+        IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(ipv6_privacy_extensions);
+
+        s = ipv6_privacy_extensions_from_string(rvalue);
+        if (s < 0) {
+                if (streq(rvalue, "kernel"))
+                        s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
+                else {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
+                        return 0;
+                }
+        }
+
+        *ipv6_privacy_extensions = s;
+
+        return 0;
+}
diff --git a/src/network/networkd-sysctl.h b/src/network/networkd-sysctl.h
new file mode 100644 (file)
index 0000000..552b552
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "conf-parser.h"
+
+typedef struct Link Link;
+
+typedef enum IPv6PrivacyExtensions {
+        /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
+        IPV6_PRIVACY_EXTENSIONS_NO,
+        IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC,
+        IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */
+        _IPV6_PRIVACY_EXTENSIONS_MAX,
+        _IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
+} IPv6PrivacyExtensions;
+
+int link_set_sysctl(Link *link);
+int link_set_ipv6_mtu(Link *link);
+
+const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
+IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);
index ce9319d942a3aa450fe438484d7e5cbd1d2cbde8..bae4ee5cbacf1ac2174eeb44d9880054c34d3883 100644 (file)
@@ -151,3 +151,15 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
 void network_config_section_free(NetworkConfigSection *cs) {
         free(cs);
 }
+
+unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
+        NetworkConfigSection *cs;
+        unsigned n = 0;
+        void *entry;
+
+        HASHMAP_FOREACH_KEY(entry, cs, hashmap)
+                if (n < cs->line)
+                        n = cs->line;
+
+        return n + 1;
+}
index 0433f883a32856417fea5b130e0fad9a59545714..ce169fa731b4b0d50973d6589847df137fc3d69e 100644 (file)
@@ -2,10 +2,13 @@
 #pragma once
 
 #include "sd-dhcp-lease.h"
+#include "sd-netlink.h"
 
 #include "conf-parser.h"
-#include "hash-funcs.h"
+#include "hashmap.h"
+#include "log.h"
 #include "macro.h"
+#include "string-util.h"
 
 typedef enum AddressFamily {
         /* This is a bitmask, though it usually doesn't feel that way! */
@@ -49,6 +52,7 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
 void network_config_section_free(NetworkConfigSection *network);
 DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
 extern const struct hash_ops network_config_hash_ops;
+unsigned hashmap_find_free_section_line(Hashmap *hashmap);
 
 static inline bool section_is_invalid(NetworkConfigSection *section) {
         /* If this returns false, then it does _not_ mean the section is valid. */
@@ -70,3 +74,10 @@ static inline bool section_is_invalid(NetworkConfigSection *section) {
         }                                                               \
         DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func);                  \
         DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
+
+static inline int log_message_warning_errno(sd_netlink_message *m, int err, const char *msg) {
+        const char *err_msg = NULL;
+
+        (void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
+        return log_warning_errno(err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
+}
index 14a8687458d5b8aebfed5cb7e947845bd18e1418..53b65286b37b42f767ea1d9207817237cbdc14ce 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-bus.h"
 
 #include "bus-util.h"
+#include "ether-addr-util.h"
 #include "netlink-internal.h"
 #include "netlink-util.h"
 #include "networkd-link.h"
index 445aee16ad0435b4f7361cb6098dac5d859837dc..f78ff9db547024b9071960d4d1a6a4bd39e812f8 100644 (file)
@@ -88,29 +88,9 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Could not load configuration files: %m");
 
-        r = manager_rtnl_enumerate_links(m);
+        r = manager_enumerate(m);
         if (r < 0)
-                return log_error_errno(r, "Could not enumerate links: %m");
-
-        r = manager_rtnl_enumerate_addresses(m);
-        if (r < 0)
-                return log_error_errno(r, "Could not enumerate addresses: %m");
-
-        r = manager_rtnl_enumerate_neighbors(m);
-        if (r < 0)
-                return log_error_errno(r, "Could not enumerate neighbors: %m");
-
-        r = manager_rtnl_enumerate_routes(m);
-        if (r < 0)
-                return log_error_errno(r, "Could not enumerate routes: %m");
-
-        r = manager_rtnl_enumerate_rules(m);
-        if (r < 0)
-                return log_error_errno(r, "Could not enumerate rules: %m");
-
-        r = manager_rtnl_enumerate_nexthop(m);
-        if (r < 0)
-                return log_error_errno(r, "Could not enumerate nexthop: %m");
+                return r;
 
         r = manager_start(m);
         if (r < 0)
index 5629ecd01a4721b833a4f209e60b1c6aaf85d35f..7c9e01aba7bfa60c9b222bad1eb495aa47e370a6 100644 (file)
@@ -123,11 +123,10 @@ int config_parse_generic_random_early_detection_u32(
                 return 0;
         }
 
-        if (v > MAX_DPs) {
+        if (v > MAX_DPs)
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Invalid '%s=', ignoring assignment: %s",
                            lvalue, rvalue);
-        }
 
         *p = v;
         qdisc = NULL;
index 30a00133d6579a9dbfe54956ef04ccf8bdfbd463..974bb8c8220d53cdcc0c7c5395276a47946f8aed 100644 (file)
@@ -21,7 +21,7 @@ void traffic_control_free(TrafficControl *tc) {
         }
 }
 
-int traffic_control_configure(Link *link, TrafficControl *tc) {
+static int traffic_control_configure(Link *link, TrafficControl *tc) {
         assert(link);
         assert(tc);
 
@@ -35,7 +35,28 @@ int traffic_control_configure(Link *link, TrafficControl *tc) {
         }
 }
 
-int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
+int link_configure_traffic_control(Link *link) {
+        TrafficControl *tc;
+        int r;
+
+        link->tc_configured = false;
+        link->tc_messages = 0;
+
+        ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) {
+                r = traffic_control_configure(link, tc);
+                if (r < 0)
+                        return r;
+        }
+
+        if (link->tc_messages == 0)
+                link->tc_configured = true;
+        else
+                log_link_debug(link, "Configuring traffic control");
+
+        return 0;
+}
+
+static int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
         assert(tc);
 
         switch(tc->kind) {
@@ -47,3 +68,14 @@ int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, boo
                 assert_not_reached("Invalid traffic control type");
         }
 }
+
+void network_drop_invalid_traffic_control(Network *network) {
+        bool has_root = false, has_clsact = false;
+        TrafficControl *tc;
+
+        assert(network);
+
+        ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section)
+                if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
+                        traffic_control_free(tc);
+}
index defa0b774a5786a52064ab06910a3b514dfe1d50..916ad3300aafffa944d7208f444ff3bae4ffaee3 100644 (file)
@@ -28,5 +28,5 @@ typedef struct TrafficControl {
 #define TC(tc) (&(tc)->meta)
 
 void traffic_control_free(TrafficControl *tc);
-int traffic_control_configure(Link *link, TrafficControl *tc);
-int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact);
+int link_configure_traffic_control(Link *link);
+void network_drop_invalid_traffic_control(Network *network);
index bc64860a353af8982138d173fd9e17505c838b81..f727d1434174e6b4f6e810460452fd3e40d29e57 100644 (file)
@@ -79,11 +79,10 @@ int config_parse_trivial_link_equalizer_id(
                            lvalue, rvalue);
                 return 0;
         }
-        if (id > INT_MAX) {
+        if (id > INT_MAX)
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "'%s=' is too large, ignoring assignment: %s",
                            lvalue, rvalue);
-        }
 
         teql->id = id;
 
index 2ac47e72f523b4d4f1fb6fc4c06a6ee67c54d64a..f6168fc3fa47484fd38ff78a1aad212838b7e07c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "alloc-util.h"
 #include "dhcp-lease-internal.h"
+#include "ether-addr-util.h"
 #include "hostname-util.h"
 #include "network-internal.h"
 #include "networkd-manager.h"
@@ -158,8 +159,10 @@ static void test_address_equality(void) {
         assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a2->in_addr) >= 0);
         assert_se(address_equal(a1, a2));
         assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a1->in_addr_peer) >= 0);
-        assert_se(address_equal(a1, a2));
+        assert_se(!address_equal(a1, a2));
         assert_se(in_addr_from_string(AF_INET, "192.168.3.11", &a2->in_addr_peer) >= 0);
+        assert_se(!address_equal(a1, a2));
+        a2->in_addr_peer = a1->in_addr_peer;
         assert_se(address_equal(a1, a2));
         a1->prefixlen = 10;
         assert_se(!address_equal(a1, a2));
@@ -170,10 +173,13 @@ static void test_address_equality(void) {
         assert_se(!address_equal(a1, a2));
 
         a2->family = AF_INET6;
+        a1->in_addr_peer = a2->in_addr_peer = IN_ADDR_NULL;
         assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr) >= 0);
         assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr) >= 0);
         assert_se(address_equal(a1, a2));
 
+        a1->prefixlen = 8;
+        assert_se(!address_equal(a1, a2));
         a2->prefixlen = 8;
         assert_se(address_equal(a1, a2));
 
@@ -252,6 +258,6 @@ int main(void) {
 
         test_network_get(manager, loopback);
 
-        assert_se(manager_rtnl_enumerate_links(manager) >= 0);
+        assert_se(manager_enumerate(manager) >= 0);
         return 0;
 }
index 5d338e6f1a3a90f92f9bb77568d80d4e1432cfe1..030e50688a4e9ecd0a94f6340dd0a970a8b3687c 100644 (file)
@@ -176,14 +176,16 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
         assert_se(network->filename = strdup("hogehoge.network"));
         assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
         assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
-        assert_se(network->n_static_addresses == 1);
+        assert_se(ordered_hashmap_size(network->addresses_by_section) == 1);
         assert_se(network_verify(network) >= 0);
-        assert_se(network->n_static_addresses == n_addresses);
+        assert_se(ordered_hashmap_size(network->addresses_by_section) == n_addresses);
         if (n_addresses > 0) {
-                assert_se(network->static_addresses);
-                assert_se(network->static_addresses->prefixlen == prefixlen);
-                assert_se(network->static_addresses->family == family);
-                assert_se(in_addr_equal(family, &network->static_addresses->in_addr, u));
+                Address *a;
+
+                assert_se(a = ordered_hashmap_first(network->addresses_by_section));
+                assert_se(a->prefixlen == prefixlen);
+                assert_se(a->family == family);
+                assert_se(in_addr_equal(family, &a->in_addr, u));
                 /* TODO: check Address.in_addr and Address.broadcast */
         }
 }
index 78755927c77f3667b305b4ea0052e52a3a9d78b5..40341d607380a43554ed69433f85c4cd9a7b66fd 100644 (file)
@@ -1,13 +1,8 @@
-/***
-  SPDX-License-Identifier: LGPL-2.1+
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fd-util.h"
 #include "fileio.h"
-#include "log.h"
-#include "macro.h"
-#include "network-internal.h"
-#include "networkd-manager.h"
+#include "networkd-routing-policy-rule.h"
 #include "string-util.h"
 #include "tests.h"
 #include "tmpfile-util.h"
index 60a59096fbc4fb819fdf495a348d0373447abf95..9445dc5b0e6e7351540f7d66de9c7e5bea8e8641 100644 (file)
@@ -660,10 +660,9 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
                         s->network_namespace_path = data.path;
                 }
 
-                if (FLAGS_SET(n, data.type)) {
+                if (FLAGS_SET(n, data.type))
                         return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
                                         "Duplicate namespace specification, refusing.");
-                }
 
                 n |= data.type;
         }
@@ -2216,14 +2215,14 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
         }
 
         v = json_variant_by_key(oci, "ociVersion");
-        if (!v) {
-                log_error("JSON file '%s' is not an OCI bundle configuration file. Refusing.", path);
-                return -EINVAL;
-        }
-        if (!streq_ptr(json_variant_string(v), "1.0.0")) {
-                log_error("OCI bundle version not supported: %s", strna(json_variant_string(v)));
-                return -EINVAL;
-        }
+        if (!v)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "JSON file '%s' is not an OCI bundle configuration file. Refusing.",
+                                       path);
+        if (!streq_ptr(json_variant_string(v), "1.0.0"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "OCI bundle version not supported: %s",
+                                       strna(json_variant_string(v)));
 
         // {
         //         _cleanup_free_ char *formatted = NULL;
index fa2002d5785adfd949930f6dd71d75c528c1bfa5..62b949f58cd2250ae16c4a4fe002fe94a3ad93e6 100644 (file)
@@ -63,16 +63,19 @@ int change_uid_gid_raw(
                 uid_t uid,
                 gid_t gid,
                 const gid_t *supplementary_gids,
-                size_t n_supplementary_gids) {
+                size_t n_supplementary_gids,
+                bool chown_stdio) {
 
         if (!uid_is_valid(uid))
                 uid = 0;
         if (!gid_is_valid(gid))
                 gid = 0;
 
-        (void) fchown(STDIN_FILENO, uid, gid);
-        (void) fchown(STDOUT_FILENO, uid, gid);
-        (void) fchown(STDERR_FILENO, uid, gid);
+        if (chown_stdio) {
+                (void) fchown(STDIN_FILENO, uid, gid);
+                (void) fchown(STDOUT_FILENO, uid, gid);
+                (void) fchown(STDERR_FILENO, uid, gid);
+        }
 
         if (setgroups(n_supplementary_gids, supplementary_gids) < 0)
                 return log_error_errno(errno, "Failed to set auxiliary groups: %m");
@@ -86,7 +89,7 @@ int change_uid_gid_raw(
         return 0;
 }
 
-int change_uid_gid(const char *user, char **_home) {
+int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
         char *x, *u, *g, *h;
         _cleanup_free_ gid_t *gids = NULL;
         _cleanup_free_ char *home = NULL, *line = NULL;
@@ -99,7 +102,7 @@ int change_uid_gid(const char *user, char **_home) {
         pid_t pid;
         int r;
 
-        assert(_home);
+        assert(ret_home);
 
         if (!user || STR_IN_SET(user, "root", "0")) {
                 /* Reset everything fully to 0, just in case */
@@ -108,7 +111,7 @@ int change_uid_gid(const char *user, char **_home) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to become root: %m");
 
-                *_home = NULL;
+                *ret_home = NULL;
                 return 0;
         }
 
@@ -232,12 +235,12 @@ int change_uid_gid(const char *user, char **_home) {
         if (r < 0 && !IN_SET(r, -EEXIST, -ENOTDIR))
                 return log_error_errno(r, "Failed to make home directory: %m");
 
-        r = change_uid_gid_raw(uid, gid, gids, n_gids);
+        r = change_uid_gid_raw(uid, gid, gids, n_gids, chown_stdio);
         if (r < 0)
                 return r;
 
-        if (_home)
-                *_home = TAKE_PTR(home);
+        if (ret_home)
+                *ret_home = TAKE_PTR(home);
 
         return 0;
 }
index 9a2b05ebbb15457e430427faf6e85251f7aec109..c82d50bdf131ebe805a8a2ad699a0781c7597b30 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-int change_uid_gid_raw(uid_t uid, gid_t gid, const gid_t *supplementary_gids, size_t n_supplementary_gids);
-int change_uid_gid(const char *user, char **ret_home);
+int change_uid_gid_raw(uid_t uid, gid_t gid, const gid_t *supplementary_gids, size_t n_supplementary_gids, bool chown_stdio);
+int change_uid_gid(const char *user, bool chown_stdio, char **ret_home);
index ea5be3f72dadc2505e35cf9f5e004f0425ab45fb..5db08cb5b3a65c8fd4cb950fe73ceece1ef61bef 100644 (file)
@@ -2726,7 +2726,7 @@ static int setup_machine_id(const char *directory) {
 
         etc_machine_id = prefix_roota(directory, "/etc/machine-id");
 
-        r = id128_read(etc_machine_id, ID128_PLAIN, &id);
+        r = id128_read(etc_machine_id, ID128_PLAIN_OR_UNINIT, &id);
         if (r < 0) {
                 if (!IN_SET(r, -ENOENT, -ENOMEDIUM)) /* If the file is missing or empty, we don't mind */
                         return log_error_errno(r, "Failed to read machine ID from container image: %m");
@@ -3321,9 +3321,9 @@ static int inner_child(
                 return log_error_errno(errno, "Failed to set PR_SET_KEEPCAPS: %m");
 
         if (uid_is_valid(arg_uid) || gid_is_valid(arg_gid))
-                r = change_uid_gid_raw(arg_uid, arg_gid, arg_supplementary_gids, arg_n_supplementary_gids);
+                r = change_uid_gid_raw(arg_uid, arg_gid, arg_supplementary_gids, arg_n_supplementary_gids, arg_console_mode != CONSOLE_PIPE);
         else
-                r = change_uid_gid(arg_user, &home);
+                r = change_uid_gid(arg_user, arg_console_mode != CONSOLE_PIPE, &home);
         if (r < 0)
                 return r;
 
@@ -4342,7 +4342,7 @@ static int load_settings(void) {
 
         /* If all settings are masked, there's no point in looking for
          * the settings file */
-        if ((arg_settings_mask & _SETTINGS_MASK_ALL) == _SETTINGS_MASK_ALL)
+        if (FLAGS_SET(arg_settings_mask, _SETTINGS_MASK_ALL))
                 return 0;
 
         fn = strjoina(arg_machine, ".nspawn");
@@ -5134,9 +5134,12 @@ static int run(int argc, char *argv[]) {
         if (r <= 0)
                 goto finish;
 
-        r = must_be_root();
-        if (r < 0)
+        if (geteuid() != 0) {
+                r = log_warning_errno(SYNTHETIC_ERRNO(EPERM),
+                                      argc >= 2 ? "Need to be root." :
+                                      "Need to be root (and some arguments are usually required).\nHint: try --help");
                 goto finish;
+        }
 
         r = cant_be_in_netns();
         if (r < 0)
index 0e8c13f7ea2cd515fed39325e6a2008c2d451d54..06ac335b291a9deb9be1bf46e244fb8d3a63cfe2 100644 (file)
@@ -595,7 +595,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
                                 new_size = limit;
 
                         /* Enlarge buffer */
-                        new_groups = realloc(*groupsp, new_size * sizeof(**groupsp));
+                        new_groups = reallocarray(*groupsp, new_size, sizeof(**groupsp));
                         if (!new_groups) {
                                 UNPROTECT_ERRNO;
                                 *errnop = ENOMEM;
diff --git a/src/oom/meson.build b/src/oom/meson.build
new file mode 100644 (file)
index 0000000..78c92de
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
+systemd_oomd_sources = files('''
+        oomd-manager-bus.c
+        oomd-manager-bus.h
+        oomd-manager.c
+        oomd-manager.h
+        oomd-util.c
+        oomd-util.h
+        oomd.c
+'''.split())
+
+oomctl_sources = files('''
+        oomctl.c
+'''.split())
+
+if conf.get('ENABLE_OOMD') == 1
+        tests += [
+                [['src/oom/test-oomd-util.c',
+                  'src/oom/oomd-util.c',
+                  'src/oom/oomd-util.h'],
+                 [],
+                 []]
+        ]
+
+        install_data('org.freedesktop.oom1.conf',
+                     install_dir : dbuspolicydir)
+
+        install_data('org.freedesktop.oom1.service',
+                     install_dir : dbussystemservicedir)
+
+        install_data('oomd.conf',
+                     install_dir : pkgsysconfdir)
+endif
diff --git a/src/oom/oomctl.c b/src/oom/oomctl.c
new file mode 100644 (file)
index 0000000..01e43d3
--- /dev/null
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "bus-error.h"
+#include "copy.h"
+#include "main-func.h"
+#include "pretty-print.h"
+#include "terminal-util.h"
+#include "verbs.h"
+
+static PagerFlags arg_pager_flags = 0;
+
+static int help(int argc, char *argv[], void *userdata) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        (void) pager_open(arg_pager_flags);
+
+        r = terminal_urlify_man("oomctl", "1", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
+               "%2$sManage or inspect the userspace OOM killer.%3$s\n"
+               "\n%4$sCommands:%5$s\n"
+               "  dump                        Output the current state of systemd-oomd\n"
+               "\n%4$sOptions:%5$s\n"
+               "  -h --help                   Show this help\n"
+               "     --version                Show package version\n"
+               "     --no-pager               Do not pipe output into a pager\n"
+               "\nSee the %6$s for details.\n"
+               , program_invocation_short_name
+               , ansi_highlight(), ansi_normal()
+               , ansi_underline(), ansi_normal()
+               , link
+        );
+
+        return 0;
+}
+
+static int dump_state(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int fd = -1;
+        int r;
+
+        r = sd_bus_open_system(&bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect system bus: %m");
+
+        (void) pager_open(arg_pager_flags);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.oom1",
+                        "/org/freedesktop/oom1",
+                        "org.freedesktop.oom1.Manager",
+                        "DumpByFileDescriptor",
+                        &error,
+                        &reply,
+                        NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to dump context: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_read(reply, "h", &fd);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        fflush(stdout);
+        return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
+}
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_NO_PAGER,
+        };
+
+        static const struct option options[] = {
+                { "help",     no_argument, NULL, 'h'          },
+                { "version",  no_argument, NULL, ARG_VERSION  },
+                { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+                {}
+        };
+
+        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_NO_PAGER:
+                                arg_pager_flags |= PAGER_DISABLE;
+                                break;
+
+                        case '?':
+                                return -EINVAL;
+
+                        default:
+                                assert_not_reached("Invalid option passed.");
+                }
+
+        return 1;
+}
+
+static int run(int argc, char* argv[]) {
+        static const Verb verbs[] = {
+                { "help", VERB_ANY, VERB_ANY, 0,            help       },
+                { "dump", VERB_ANY, 1,        VERB_DEFAULT, dump_state },
+                {}
+        };
+
+        int r;
+
+        log_show_color(true);
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r;
+
+        return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/oom/oomd-manager-bus.c b/src/oom/oomd-manager-bus.c
new file mode 100644 (file)
index 0000000..0f39a60
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/capability.h>
+
+#include "bus-common-errors.h"
+#include "bus-polkit.h"
+#include "fd-util.h"
+#include "oomd-manager-bus.h"
+#include "oomd-manager.h"
+#include "user-util.h"
+
+static int bus_method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_free_ char *dump = NULL;
+        _cleanup_close_ int fd = -1;
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = manager_get_dump_string(m, &dump);
+        if (r < 0)
+                return r;
+
+        fd = acquire_data_fd(dump, strlen(dump), 0);
+        if (fd < 0)
+                return fd;
+
+        return sd_bus_reply_method_return(message, "h", fd);
+}
+
+static const sd_bus_vtable manager_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_METHOD_WITH_NAMES("DumpByFileDescriptor",
+                                 NULL,,
+                                 "h",
+                                 SD_BUS_PARAM(fd),
+                                 bus_method_dump_by_fd,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/oom1",
+        "org.freedesktop.oom1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+};
diff --git a/src/oom/oomd-manager-bus.h b/src/oom/oomd-manager-bus.h
new file mode 100644 (file)
index 0000000..6dd576d
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "bus-object.h"
+
+typedef struct Manager Manager;
+
+extern const BusObjectImplementation manager_object;
diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c
new file mode 100644 (file)
index 0000000..6b75fc3
--- /dev/null
@@ -0,0 +1,546 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-log-control-api.h"
+#include "bus-util.h"
+#include "bus-polkit.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "oomd-manager-bus.h"
+#include "oomd-manager.h"
+#include "path-util.h"
+
+typedef struct ManagedOOMReply {
+        ManagedOOMMode mode;
+        char *path;
+        char *property;
+        unsigned limit;
+} ManagedOOMReply;
+
+static void managed_oom_reply_destroy(ManagedOOMReply *reply) {
+        assert(reply);
+        free(reply->path);
+        free(reply->property);
+}
+
+static int managed_oom_mode(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        ManagedOOMMode *mode = userdata, m;
+        const char *s;
+
+        assert(mode);
+        assert_se(s = json_variant_string(v));
+
+        m = managed_oom_mode_from_string(s);
+        if (m < 0)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "%s is not a valid ManagedOOMMode", s);
+
+        *mode = m;
+        return 0;
+}
+
+static int process_managed_oom_reply(
+                Varlink *link,
+                JsonVariant *parameters,
+                const char *error_id,
+                VarlinkReplyFlags flags,
+                void *userdata) {
+        JsonVariant *c, *cgroups;
+        Manager *m = userdata;
+        int r = 0;
+
+        assert(m);
+
+        static const JsonDispatch dispatch_table[] = {
+                { "mode",     JSON_VARIANT_STRING,   managed_oom_mode,       offsetof(ManagedOOMReply, mode),     JSON_MANDATORY },
+                { "path",     JSON_VARIANT_STRING,   json_dispatch_string,   offsetof(ManagedOOMReply, path),     JSON_MANDATORY },
+                { "property", JSON_VARIANT_STRING,   json_dispatch_string,   offsetof(ManagedOOMReply, property), JSON_MANDATORY },
+                { "limit",    JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(ManagedOOMReply, limit),    0 },
+                {},
+        };
+
+        if (error_id) {
+                r = -EIO;
+                log_debug("Error getting ManagedOOM cgroups: %s", error_id);
+                goto finish;
+        }
+
+        cgroups = json_variant_by_key(parameters, "cgroups");
+        if (!cgroups) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        /* Skip malformed elements and keep processing in case the others are good */
+        JSON_VARIANT_ARRAY_FOREACH(c, cgroups) {
+                _cleanup_(managed_oom_reply_destroy) ManagedOOMReply reply = {};
+                OomdCGroupContext *ctx;
+                Hashmap *monitor_hm;
+                loadavg_t limit;
+                int ret;
+
+                if (!json_variant_is_object(c))
+                        continue;
+
+                ret = json_dispatch(c, dispatch_table, NULL, 0, &reply);
+                if (ret == -ENOMEM) {
+                        r = ret;
+                        goto finish;
+                } else if (ret < 0)
+                        continue;
+
+                monitor_hm = streq(reply.property, "ManagedOOMSwap") ?
+                                m->monitored_swap_cgroup_contexts : m->monitored_mem_pressure_cgroup_contexts;
+
+                if (reply.mode == MANAGED_OOM_AUTO) {
+                        (void) oomd_cgroup_context_free(hashmap_remove(monitor_hm, reply.path));
+                        continue;
+                }
+
+                limit = m->default_mem_pressure_limit;
+
+                if (streq(reply.property, "ManagedOOMMemoryPressure")) {
+                        if (reply.limit > 100)
+                                continue;
+                        else if (reply.limit != 0) {
+                                ret = store_loadavg_fixed_point((unsigned long) reply.limit, 0, &limit);
+                                if (ret < 0)
+                                        continue;
+                        }
+                }
+
+                ret = oomd_insert_cgroup_context(NULL, monitor_hm, reply.path);
+                if (ret == -ENOMEM) {
+                        r = ret;
+                        goto finish;
+                }
+
+                /* Always update the limit in case it was changed. For non-memory pressure detection the value is
+                 * ignored so always updating it here is not a problem. */
+                ctx = hashmap_get(monitor_hm, reply.path);
+                if (ctx)
+                        ctx->mem_pressure_limit = limit;
+        }
+
+finish:
+        if (!FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
+                m->varlink = varlink_close_unref(link);
+
+        return r;
+}
+
+/* Fill `new_h` with `path`'s descendent OomdCGroupContexts. Only include descendent cgroups that are possible
+ * candidates for action. That is, only leaf cgroups or cgroups with memory.oom.group set to "1".
+ *
+ * This function ignores most errors in order to handle cgroups that may have been cleaned up while populating
+ * the hashmap.
+ *
+ * `new_h` is of the form { key: cgroup paths -> value: OomdCGroupContext } */
+static int recursively_get_cgroup_context(Hashmap *new_h, const char *path) {
+        _cleanup_free_ char *subpath = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
+        int r;
+
+        assert(new_h);
+        assert(path);
+
+        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d);
+        if (r < 0)
+                return r;
+
+        r = cg_read_subgroup(d, &subpath);
+        if (r < 0)
+                return r;
+        else if (r == 0) { /* No subgroups? We're a leaf node */
+                r = oomd_insert_cgroup_context(NULL, new_h, path);
+                return (r == -ENOMEM) ? r : 0;
+        }
+
+        do {
+                _cleanup_free_ char *cg_path = NULL;
+                bool oom_group;
+
+                cg_path = path_join(empty_to_root(path), subpath);
+                if (!cg_path)
+                        return -ENOMEM;
+
+                subpath = mfree(subpath);
+
+                r = cg_get_attribute_as_bool("memory", cg_path, "memory.oom.group", &oom_group);
+                /* The cgroup might be gone. Skip it as a candidate since we can't get information on it. */
+                if (r < 0)
+                        return (r == -ENOMEM) ? r : 0;
+
+                if (oom_group)
+                        r = oomd_insert_cgroup_context(NULL, new_h, cg_path);
+                else
+                        r = recursively_get_cgroup_context(new_h, cg_path);
+                if (r == -ENOMEM)
+                        return r;
+        } while ((r = cg_read_subgroup(d, &subpath)) > 0);
+
+        return 0;
+}
+
+static int update_monitored_cgroup_contexts(Hashmap **monitored_cgroups) {
+        _cleanup_hashmap_free_ Hashmap *new_base = NULL;
+        OomdCGroupContext *ctx;
+        int r;
+
+        assert(monitored_cgroups);
+
+        new_base = hashmap_new(&oomd_cgroup_ctx_hash_ops);
+        if (!new_base)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(ctx, *monitored_cgroups) {
+                /* Skip most errors since the cgroup we're trying to update might not exist anymore. */
+                r = oomd_insert_cgroup_context(*monitored_cgroups, new_base, ctx->path);
+                if (r == -ENOMEM)
+                        return r;
+        }
+
+        hashmap_free(*monitored_cgroups);
+        *monitored_cgroups = TAKE_PTR(new_base);
+
+        return 0;
+}
+
+static int get_monitored_cgroup_contexts_candidates(Hashmap *monitored_cgroups, Hashmap **ret_candidates) {
+        _cleanup_hashmap_free_ Hashmap *candidates = NULL;
+        OomdCGroupContext *ctx;
+        int r;
+
+        assert(monitored_cgroups);
+        assert(ret_candidates);
+
+        candidates = hashmap_new(&oomd_cgroup_ctx_hash_ops);
+        if (!candidates)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(ctx, monitored_cgroups) {
+                r = recursively_get_cgroup_context(candidates, ctx->path);
+                if (r == -ENOMEM)
+                        return r;
+        }
+
+        *ret_candidates = TAKE_PTR(candidates);
+
+        return 0;
+}
+
+static int acquire_managed_oom_connect(Manager *m) {
+        _cleanup_(varlink_close_unrefp) Varlink *link = NULL;
+        int r;
+
+        assert(m);
+        assert(m->event);
+
+        r = varlink_connect_address(&link, VARLINK_ADDR_PATH_MANAGED_OOM);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to %s: %m", VARLINK_ADDR_PATH_MANAGED_OOM);
+
+        (void) varlink_set_userdata(link, m);
+        (void) varlink_set_description(link, "oomd");
+        (void) varlink_set_relative_timeout(link, USEC_INFINITY);
+
+        r = varlink_attach_event(link, m->event, SD_EVENT_PRIORITY_NORMAL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
+
+        r = varlink_bind_reply(link, process_managed_oom_reply);
+        if (r < 0)
+                return log_error_errno(r, "Failed to bind reply callback: %m");
+
+        r = varlink_observe(link, "io.systemd.ManagedOOM.SubscribeManagedOOMCGroups", NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to observe varlink call: %m");
+
+        m->varlink = TAKE_PTR(link);
+        return 0;
+}
+
+static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        _cleanup_set_free_ Set *targets = NULL;
+        Manager *m = userdata;
+        usec_t usec_now;
+        int r;
+
+        assert(s);
+        assert(userdata);
+
+        /* Reset timer */
+        r = sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &usec_now);
+        if (r < 0)
+                return log_error_errno(r, "Failed to reset event timer");
+
+        r = sd_event_source_set_time_relative(s, INTERVAL_USEC);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set relative time for timer");
+
+        /* Reconnect if our connection dropped */
+        if (!m->varlink) {
+                r = acquire_managed_oom_connect(m);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to acquire varlink connection");
+        }
+
+        /* Update the cgroups used for detection/action */
+        r = update_monitored_cgroup_contexts(&m->monitored_swap_cgroup_contexts);
+        if (r == -ENOMEM)
+                return log_error_errno(r, "Failed to update monitored swap cgroup contexts");
+
+        r = update_monitored_cgroup_contexts(&m->monitored_mem_pressure_cgroup_contexts);
+        if (r == -ENOMEM)
+                return log_error_errno(r, "Failed to update monitored memory pressure cgroup contexts");
+
+        r = oomd_system_context_acquire("/proc/swaps", &m->system_context);
+        /* If there aren't units depending on swap actions, the only error we exit on is ENOMEM */
+        if (r == -ENOMEM || (r < 0 && !hashmap_isempty(m->monitored_swap_cgroup_contexts)))
+                return log_error_errno(r, "Failed to acquire system context");
+
+        /* If we're still recovering from a kill, don't try to kill again yet */
+        if (m->post_action_delay_start > 0) {
+                if (m->post_action_delay_start + POST_ACTION_DELAY_USEC > usec_now)
+                        return 0;
+                else
+                        m->post_action_delay_start = 0;
+        }
+
+        r = oomd_pressure_above(m->monitored_mem_pressure_cgroup_contexts, PRESSURE_DURATION_USEC, &targets);
+        if (r == -ENOMEM)
+                return log_error_errno(r, "Failed to check if memory pressure exceeded limits");
+        else if (r == 1) {
+                /* Check if there was reclaim activity in the last interval. The concern is the following case:
+                 * Pressure climbed, a lot of high-frequency pages were reclaimed, and we killed the offending
+                 * cgroup. Even after this, well-behaved processes will fault in recently resident pages and
+                 * this will cause pressure to remain high. Thus if there isn't any reclaim pressure, no need
+                 * to kill something (it won't help anyways). */
+                if (oomd_memory_reclaim(m->monitored_mem_pressure_cgroup_contexts)) {
+                        _cleanup_hashmap_free_ Hashmap *candidates = NULL;
+                        OomdCGroupContext *t;
+
+                        r = get_monitored_cgroup_contexts_candidates(m->monitored_mem_pressure_cgroup_contexts, &candidates);
+                        if (r == -ENOMEM)
+                                return log_error_errno(r, "Failed to get monitored memory pressure cgroup candidates");
+
+                        SET_FOREACH(t, targets) {
+                                log_notice("Memory pressure for %s is greater than %lu for more than %"PRIu64" seconds and there was reclaim activity",
+                                        t->path, LOAD_INT(t->mem_pressure_limit), PRESSURE_DURATION_USEC / USEC_PER_SEC);
+
+                                r = oomd_kill_by_pgscan(candidates, t->path, m->dry_run);
+                                if (r == -ENOMEM)
+                                        return log_error_errno(r, "Failed to kill cgroup processes by pgscan");
+                                if (r < 0)
+                                        log_info("Failed to kill any cgroup(s) under %s based on pressure", t->path);
+                                else {
+                                        /* Don't act on all the high pressure cgroups at once; return as soon as we kill one */
+                                        m->post_action_delay_start = usec_now;
+                                        return 0;
+                                }
+                        }
+                }
+        }
+
+        if (oomd_swap_free_below(&m->system_context, (100 - m->swap_used_limit))) {
+                _cleanup_hashmap_free_ Hashmap *candidates = NULL;
+
+                log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than %u%%",
+                        m->system_context.swap_used, m->system_context.swap_total, m->swap_used_limit);
+
+                r = get_monitored_cgroup_contexts_candidates(m->monitored_swap_cgroup_contexts, &candidates);
+                if (r == -ENOMEM)
+                        return log_error_errno(r, "Failed to get monitored swap cgroup candidates");
+
+                r = oomd_kill_by_swap_usage(candidates, m->dry_run);
+                if (r == -ENOMEM)
+                        return log_error_errno(r, "Failed to kill cgroup processes by swap usage");
+                if (r < 0)
+                        log_info("Failed to kill any cgroup(s) based on swap");
+                else {
+                        m->post_action_delay_start = usec_now;
+                        return 0;
+                }
+        }
+
+        return 0;
+}
+
+static int monitor_cgroup_contexts(Manager *m) {
+        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+        int r;
+
+        assert(m);
+        assert(m->event);
+
+        r = sd_event_add_time(m->event, &s, CLOCK_MONOTONIC, 0, 0, monitor_cgroup_contexts_handler, m);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_exit_on_failure(s, true);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_enabled(s, SD_EVENT_ON);
+        if (r < 0)
+                return r;
+
+        (void) sd_event_source_set_description(s, "oomd-timer");
+
+        m->cgroup_context_event_source = TAKE_PTR(s);
+        return 0;
+}
+
+void manager_free(Manager *m) {
+        assert(m);
+
+        varlink_close_unref(m->varlink);
+        sd_event_source_unref(m->cgroup_context_event_source);
+        sd_event_unref(m->event);
+
+        bus_verify_polkit_async_registry_free(m->polkit_registry);
+        sd_bus_flush_close_unref(m->bus);
+
+        hashmap_free(m->monitored_swap_cgroup_contexts);
+        hashmap_free(m->monitored_mem_pressure_cgroup_contexts);
+
+        free(m);
+}
+
+int manager_new(Manager **ret) {
+        _cleanup_(manager_freep) Manager *m = NULL;
+        int r;
+
+        assert(ret);
+
+        m = new0(Manager, 1);
+        if (!m)
+                return -ENOMEM;
+
+        r = sd_event_default(&m->event);
+        if (r < 0)
+                return r;
+
+        (void) sd_event_set_watchdog(m->event, true);
+
+        r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+        if (r < 0)
+                return r;
+
+        r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
+        if (r < 0)
+                return r;
+
+        m->monitored_swap_cgroup_contexts = hashmap_new(&oomd_cgroup_ctx_hash_ops);
+        if (!m->monitored_swap_cgroup_contexts)
+                return -ENOMEM;
+
+        m->monitored_mem_pressure_cgroup_contexts = hashmap_new(&oomd_cgroup_ctx_hash_ops);
+        if (!m->monitored_mem_pressure_cgroup_contexts)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(m);
+        return 0;
+}
+
+static int manager_connect_bus(Manager *m) {
+        int r;
+
+        assert(m);
+        assert(!m->bus);
+
+        r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-oom");
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to bus: %m");
+
+        r = bus_add_implementation(m->bus, &manager_object, m);
+        if (r < 0)
+                return r;
+
+        r = bus_log_control_api_register(m->bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.oom1", 0, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to request name: %m");
+
+        r = sd_bus_attach_event(m->bus, m->event, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach bus to event loop: %m");
+
+        return 0;
+}
+
+int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit) {
+        unsigned long l;
+        int r;
+
+        assert(m);
+
+        m->dry_run = dry_run;
+
+        m->swap_used_limit = swap_used_limit != -1 ? swap_used_limit : DEFAULT_SWAP_USED_LIMIT;
+        assert(m->swap_used_limit <= 100);
+
+        l = mem_pressure_limit != -1 ? mem_pressure_limit : DEFAULT_MEM_PRESSURE_LIMIT;
+        r = store_loadavg_fixed_point(l, 0, &m->default_mem_pressure_limit);
+        if (r < 0)
+                return r;
+
+        r = manager_connect_bus(m);
+        if (r < 0)
+                return r;
+
+        r = acquire_managed_oom_connect(m);
+        if (r < 0)
+                return r;
+
+        r = monitor_cgroup_contexts(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int manager_get_dump_string(Manager *m, char **ret) {
+        _cleanup_free_ char *dump = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        OomdCGroupContext *c;
+        size_t size;
+        char *key;
+        int r;
+
+        assert(m);
+        assert(ret);
+
+        f = open_memstream_unlocked(&dump, &size);
+        if (!f)
+                return -errno;
+
+        fprintf(f,
+                "Dry Run: %s\n"
+                "Swap Used Limit: %u%%\n"
+                "Default Memory Pressure Limit: %lu%%\n"
+                "System Context:\n",
+                yes_no(m->dry_run),
+                m->swap_used_limit,
+                LOAD_INT(m->default_mem_pressure_limit));
+        oomd_dump_system_context(&m->system_context, f, "\t");
+
+        fprintf(f, "Swap Monitored CGroups:\n");
+        HASHMAP_FOREACH_KEY(c, key, m->monitored_swap_cgroup_contexts)
+                oomd_dump_swap_cgroup_context(c, f, "\t");
+
+        fprintf(f, "Memory Pressure Monitored CGroups:\n");
+        HASHMAP_FOREACH_KEY(c, key, m->monitored_mem_pressure_cgroup_contexts)
+                oomd_dump_memory_pressure_cgroup_context(c, f, "\t");
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return r;
+
+        f = safe_fclose(f);
+
+        *ret = TAKE_PTR(dump);
+        return 0;
+}
diff --git a/src/oom/oomd-manager.h b/src/oom/oomd-manager.h
new file mode 100644 (file)
index 0000000..b5c2497
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "conf-parser.h"
+#include "oomd-util.h"
+#include "sd-event.h"
+#include "varlink.h"
+
+/* Polling interval for monitoring stats */
+#define INTERVAL_USEC (1 * USEC_PER_SEC)
+
+/* Used to weight the averages */
+#define AVERAGE_SIZE_DECAY 4
+
+/* Take action if 10s of memory pressure > 60 for more than 30s. We use the "full" value from PSI so this is the
+ * percentage of time all tasks were delayed (i.e. unproductive).
+ * Generally 60 or higher might be acceptable for something like system.slice with no memory.high set; processes in
+ * system.slice are assumed to be less latency sensitive. */
+#define PRESSURE_DURATION_USEC (30 * USEC_PER_SEC)
+#define DEFAULT_MEM_PRESSURE_LIMIT 60
+#define DEFAULT_SWAP_USED_LIMIT 90
+
+#define POST_ACTION_DELAY_USEC (15 * USEC_PER_SEC)
+
+typedef struct Manager Manager;
+
+struct Manager {
+        sd_bus *bus;
+        sd_event *event;
+
+        Hashmap *polkit_registry;
+
+        bool dry_run;
+        unsigned swap_used_limit;
+        loadavg_t default_mem_pressure_limit;
+
+        /* k: cgroup paths -> v: OomdCGroupContext
+         * Used to detect when to take action. */
+        Hashmap *monitored_swap_cgroup_contexts;
+        Hashmap *monitored_mem_pressure_cgroup_contexts;
+
+        OomdSystemContext system_context;
+
+        usec_t post_action_delay_start;
+
+        sd_event_source *cgroup_context_event_source;
+
+        Varlink *varlink;
+};
+
+void manager_free(Manager *m);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+
+int manager_new(Manager **ret);
+
+int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit);
+
+int manager_get_dump_string(Manager *m, char **ret);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_oomd_default);
diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c
new file mode 100644 (file)
index 0000000..6cd4ba4
--- /dev/null
@@ -0,0 +1,451 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "oomd-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "procfs-util.h"
+#include "signal-util.h"
+#include "sort-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+                oomd_cgroup_ctx_hash_ops,
+                char,
+                string_hash_func,
+                string_compare_func,
+                OomdCGroupContext,
+                oomd_cgroup_context_free);
+
+static int log_kill(pid_t pid, int sig, void *userdata) {
+        log_debug("oomd attempting to kill " PID_FMT " with %s", pid, signal_to_string(sig));
+        return 0;
+}
+
+static int increment_oomd_xattr(const char *path, const char *xattr, uint64_t num_procs_killed) {
+        _cleanup_free_ char *value = NULL;
+        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+        uint64_t curr_count = 0;
+        int r;
+
+        assert(path);
+        assert(xattr);
+
+        r = cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, path, xattr, &value);
+        if (r < 0 && r != -ENODATA)
+                return r;
+
+        if (!isempty(value)) {
+                 r = safe_atou64(value, &curr_count);
+                 if (r < 0)
+                         return r;
+        }
+
+        if (curr_count > UINT64_MAX - num_procs_killed)
+                return -EOVERFLOW;
+
+        xsprintf(buf, "%"PRIu64, curr_count + num_procs_killed);
+        r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, path, xattr, buf, strlen(buf), 0);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+OomdCGroupContext *oomd_cgroup_context_free(OomdCGroupContext *ctx) {
+        if (!ctx)
+                return NULL;
+
+        free(ctx->path);
+        return mfree(ctx);
+}
+
+int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret) {
+        _cleanup_set_free_ Set *targets = NULL;
+        OomdCGroupContext *ctx;
+        char *key;
+        int r;
+
+        assert(h);
+        assert(ret);
+
+        targets = set_new(NULL);
+        if (!targets)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH_KEY(ctx, key, h) {
+                if (ctx->memory_pressure.avg10 > ctx->mem_pressure_limit) {
+                        usec_t diff;
+
+                        if (ctx->last_hit_mem_pressure_limit == 0)
+                                ctx->last_hit_mem_pressure_limit = now(CLOCK_MONOTONIC);
+
+                        diff = now(CLOCK_MONOTONIC) - ctx->last_hit_mem_pressure_limit;
+                        if (diff >= duration) {
+                                r = set_put(targets, ctx);
+                                if (r < 0)
+                                        return -ENOMEM;
+                        }
+                } else
+                        ctx->last_hit_mem_pressure_limit = 0;
+        }
+
+        if (!set_isempty(targets)) {
+                *ret = TAKE_PTR(targets);
+                return 1;
+        }
+
+        *ret = NULL;
+        return 0;
+}
+
+bool oomd_memory_reclaim(Hashmap *h) {
+        uint64_t pgscan = 0, pgscan_of = 0, last_pgscan = 0, last_pgscan_of = 0;
+        OomdCGroupContext *ctx;
+
+        assert(h);
+
+        /* If sum of all the current pgscan values are greater than the sum of all the last_pgscan values,
+         * there was reclaim activity. Used along with pressure checks to decide whether to take action. */
+
+        HASHMAP_FOREACH(ctx, h) {
+                uint64_t sum;
+
+                sum = pgscan + ctx->pgscan;
+                if (sum < pgscan || sum < ctx->pgscan)
+                        pgscan_of++; /* count overflows */
+                pgscan = sum;
+
+                sum = last_pgscan + ctx->last_pgscan;
+                if (sum < last_pgscan || sum < ctx->last_pgscan)
+                        last_pgscan_of++; /* count overflows */
+                last_pgscan = sum;
+        }
+
+        /* overflow counts are the same, return sums comparison */
+        if (last_pgscan_of == pgscan_of)
+                return pgscan > last_pgscan;
+
+        return pgscan_of > last_pgscan_of;
+}
+
+bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent) {
+        uint64_t swap_threshold;
+
+        assert(ctx);
+        assert(threshold_percent <= 100);
+
+        swap_threshold = ctx->swap_total * threshold_percent / ((uint64_t) 100);
+        return (ctx->swap_total - ctx->swap_used) < swap_threshold;
+}
+
+int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const char *prefix, OomdCGroupContext ***ret) {
+        _cleanup_free_ OomdCGroupContext **sorted = NULL;
+        OomdCGroupContext *item;
+        size_t k = 0;
+
+        assert(h);
+        assert(compare_func);
+        assert(ret);
+
+        sorted = new0(OomdCGroupContext*, hashmap_size(h));
+        if (!sorted)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(item, h) {
+                if (item->path && prefix && !path_startswith(item->path, prefix))
+                        continue;
+
+                sorted[k++] = item;
+        }
+
+        typesafe_qsort(sorted, k, compare_func);
+
+        *ret = TAKE_PTR(sorted);
+
+        assert(k <= INT_MAX);
+        return (int) k;
+}
+
+int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run) {
+        _cleanup_set_free_ Set *pids_killed = NULL;
+        int r;
+
+        assert(path);
+
+        if (dry_run) {
+                _cleanup_free_ char *cg_path = NULL;
+
+                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &cg_path);
+                if (r < 0)
+                        return r;
+
+                log_debug("oomd dry-run: Would have tried to kill %s with recurse=%s", cg_path, true_false(recurse));
+                return 0;
+        }
+
+        pids_killed = set_new(NULL);
+        if (!pids_killed)
+                return -ENOMEM;
+
+        if (recurse)
+                r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, path, SIGKILL, CGROUP_IGNORE_SELF, pids_killed, log_kill, NULL);
+        else
+                r = cg_kill(SYSTEMD_CGROUP_CONTROLLER, path, SIGKILL, CGROUP_IGNORE_SELF, pids_killed, log_kill, NULL);
+        if (r < 0)
+                return r;
+
+        r = increment_oomd_xattr(path, "user.systemd_oomd_kill", set_size(pids_killed));
+        if (r < 0)
+                log_debug_errno(r, "Failed to set user.systemd_oomd_kill on kill: %m");
+
+        return set_size(pids_killed) != 0;
+}
+
+int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run) {
+        _cleanup_free_ OomdCGroupContext **sorted = NULL;
+        int r;
+
+        assert(h);
+
+        r = oomd_sort_cgroup_contexts(h, compare_pgscan, prefix, &sorted);
+        if (r < 0)
+                return r;
+
+        for (int i = 0; i < r; i++) {
+                if (sorted[i]->pgscan == 0)
+                        break;
+
+                r = oomd_cgroup_kill(sorted[i]->path, true, dry_run);
+                if (r > 0 || r == -ENOMEM)
+                        break;
+        }
+
+        return r;
+}
+
+int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run) {
+        _cleanup_free_ OomdCGroupContext **sorted = NULL;
+        int r;
+
+        assert(h);
+
+        r = oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted);
+        if (r < 0)
+                return r;
+
+        /* Try to kill cgroups with non-zero swap usage until we either succeed in
+         * killing or we get to a cgroup with no swap usage. */
+        for (int i = 0; i < r; i++) {
+                if (sorted[i]->swap_usage == 0)
+                        break;
+
+                r = oomd_cgroup_kill(sorted[i]->path, true, dry_run);
+                if (r > 0 || r == -ENOMEM)
+                        break;
+        }
+
+        return r;
+}
+
+int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) {
+        _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL;
+        _cleanup_free_ char *p = NULL, *val = NULL;
+        bool is_root;
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        ctx = new0(OomdCGroupContext, 1);
+        if (!ctx)
+                return -ENOMEM;
+
+        is_root = empty_or_root(path);
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, "memory.pressure", &p);
+        if (r < 0)
+                return log_debug_errno(r, "Error getting cgroup memory pressure path from %s: %m", path);
+
+        r = read_resource_pressure(p, PRESSURE_TYPE_FULL, &ctx->memory_pressure);
+        if (r < 0)
+                return log_debug_errno(r, "Error parsing memory pressure from %s: %m", p);
+
+        if (is_root) {
+                r = procfs_memory_get_used(&ctx->current_memory_usage);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting memory used from procfs: %m");
+        } else {
+                r = cg_get_attribute_as_uint64(SYSTEMD_CGROUP_CONTROLLER, path, "memory.current", &ctx->current_memory_usage);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting memory.current from %s: %m", path);
+
+                r = cg_get_attribute_as_uint64(SYSTEMD_CGROUP_CONTROLLER, path, "memory.min", &ctx->memory_min);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting memory.min from %s: %m", path);
+
+                r = cg_get_attribute_as_uint64(SYSTEMD_CGROUP_CONTROLLER, path, "memory.low", &ctx->memory_low);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting memory.low from %s: %m", path);
+
+                r = cg_get_attribute_as_uint64(SYSTEMD_CGROUP_CONTROLLER, path, "memory.swap.current", &ctx->swap_usage);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting memory.swap.current from %s: %m", path);
+
+                r = cg_get_keyed_attribute(SYSTEMD_CGROUP_CONTROLLER, path, "memory.stat", STRV_MAKE("pgscan"), &val);
+                if (r < 0)
+                        return log_debug_errno(r, "Error getting pgscan from memory.stat under %s: %m", path);
+
+                r = safe_atou64(val, &ctx->pgscan);
+                if (r < 0)
+                        return log_debug_errno(r, "Error converting pgscan value to uint64_t: %m");
+        }
+
+        ctx->path = strdup(empty_to_root(path));
+        if (!ctx->path)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(ctx);
+        return 0;
+}
+
+int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext *ret) {
+        _cleanup_fclose_ FILE *f = NULL;
+        OomdSystemContext ctx = {};
+        int r;
+
+        assert(proc_swaps_path);
+        assert(ret);
+
+        f = fopen(proc_swaps_path, "re");
+        if (!f)
+                return -errno;
+
+        (void) fscanf(f, "%*s %*s %*s %*s %*s\n");
+
+        for (;;) {
+                uint64_t total, used;
+
+                r = fscanf(f,
+                           "%*s "          /* device/file */
+                           "%*s "          /* type of swap */
+                           "%" PRIu64 " "  /* swap size */
+                           "%" PRIu64 " "  /* used */
+                           "%*s\n",        /* priority */
+                           &total, &used);
+
+                if (r == EOF && feof(f))
+                         break;
+
+                if (r != 2) {
+                        if (ferror(f))
+                                return log_debug_errno(errno, "Error reading from %s: %m", proc_swaps_path);
+
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+                                               "Failed to parse values from %s: %m", proc_swaps_path);
+                }
+
+                ctx.swap_total += total * 1024U;
+                ctx.swap_used += used * 1024U;
+        }
+
+        *ret = ctx;
+        return 0;
+}
+
+int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path) {
+        _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *curr_ctx = NULL;
+        OomdCGroupContext *old_ctx, *ctx;
+        int r;
+
+        assert(new_h);
+        assert(path);
+
+        r = oomd_cgroup_context_acquire(path, &curr_ctx);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get OomdCGroupContext for %s: %m", path);
+
+        old_ctx = hashmap_get(old_h, path);
+        if (old_ctx) {
+                curr_ctx->last_pgscan = old_ctx->pgscan;
+                curr_ctx->mem_pressure_limit = old_ctx->mem_pressure_limit;
+                curr_ctx->last_hit_mem_pressure_limit = old_ctx->last_hit_mem_pressure_limit;
+        }
+
+        ctx = TAKE_PTR(curr_ctx);
+        r = hashmap_put(new_h, ctx->path, ctx);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix) {
+        char swap[FORMAT_BYTES_MAX];
+
+        assert(ctx);
+        assert(f);
+
+        if (!empty_or_root(ctx->path))
+                fprintf(f,
+                        "%sPath: %s\n"
+                        "%s\tSwap Usage: %s\n",
+                        strempty(prefix), ctx->path,
+                        strempty(prefix), format_bytes(swap, sizeof(swap), ctx->swap_usage));
+        else
+                fprintf(f,
+                        "%sPath: %s\n"
+                        "%s\tSwap Usage: (see System Context)\n",
+                        strempty(prefix), ctx->path,
+                        strempty(prefix));
+}
+
+void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix) {
+        char tbuf[FORMAT_TIMESPAN_MAX], mem_use[FORMAT_BYTES_MAX];
+        char mem_min[FORMAT_BYTES_MAX], mem_low[FORMAT_BYTES_MAX];
+
+        assert(ctx);
+        assert(f);
+
+        fprintf(f,
+                "%sPath: %s\n"
+                "%s\tMemory Pressure Limit: %lu%%\n"
+                "%s\tPressure: Avg10: %lu.%02lu Avg60: %lu.%02lu Avg300: %lu.%02lu Total: %s\n"
+                "%s\tCurrent Memory Usage: %s\n",
+                strempty(prefix), ctx->path,
+                strempty(prefix), LOAD_INT(ctx->mem_pressure_limit),
+                strempty(prefix),
+                LOAD_INT(ctx->memory_pressure.avg10), LOAD_FRAC(ctx->memory_pressure.avg10),
+                LOAD_INT(ctx->memory_pressure.avg60), LOAD_FRAC(ctx->memory_pressure.avg60),
+                LOAD_INT(ctx->memory_pressure.avg300), LOAD_FRAC(ctx->memory_pressure.avg300),
+                format_timespan(tbuf, sizeof(tbuf), ctx->memory_pressure.total, USEC_PER_SEC),
+                strempty(prefix), format_bytes(mem_use, sizeof(mem_use), ctx->current_memory_usage));
+
+        if (!empty_or_root(ctx->path))
+                fprintf(f,
+                        "%s\tMemory Min: %s\n"
+                        "%s\tMemory Low: %s\n"
+                        "%s\tPgscan: %" PRIu64 "\n",
+                        strempty(prefix), format_bytes_cgroup_protection(mem_min, sizeof(mem_min), ctx->memory_min),
+                        strempty(prefix), format_bytes_cgroup_protection(mem_low, sizeof(mem_low), ctx->memory_low),
+                        strempty(prefix), ctx->pgscan);
+}
+
+void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix) {
+        char used[FORMAT_BYTES_MAX], total[FORMAT_BYTES_MAX];
+
+        assert(ctx);
+        assert(f);
+
+        fprintf(f,
+                "%sSwap: Used: %s Total: %s\n",
+                strempty(prefix),
+                format_bytes(used, sizeof(used), ctx->swap_used),
+                format_bytes(total, sizeof(total), ctx->swap_total));
+}
diff --git a/src/oom/oomd-util.h b/src/oom/oomd-util.h
new file mode 100644 (file)
index 0000000..cfd717a
--- /dev/null
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "hashmap.h"
+#include "psi-util.h"
+
+#define GROWING_SIZE_PERCENTILE 80
+
+extern const struct hash_ops oomd_cgroup_ctx_hash_ops;
+
+typedef struct OomdCGroupContext OomdCGroupContext;
+typedef struct OomdSystemContext OomdSystemContext;
+
+typedef int (oomd_compare_t)(OomdCGroupContext * const *, OomdCGroupContext * const *);
+
+struct OomdCGroupContext {
+        char *path;
+
+        ResourcePressure memory_pressure;
+
+        uint64_t current_memory_usage;
+
+        uint64_t memory_min;
+        uint64_t memory_low;
+        uint64_t swap_usage;
+
+        uint64_t last_pgscan;
+        uint64_t pgscan;
+
+        /* These are only used by oomd_pressure_above for acting on high memory pressure. */
+        loadavg_t mem_pressure_limit;
+        usec_t last_hit_mem_pressure_limit;
+};
+
+struct OomdSystemContext {
+        uint64_t swap_total;
+        uint64_t swap_used;
+};
+
+OomdCGroupContext *oomd_cgroup_context_free(OomdCGroupContext *ctx);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OomdCGroupContext*, oomd_cgroup_context_free);
+
+/* All hashmaps used with these functions are expected to be of the form
+ * key: cgroup paths -> value: OomdCGroupContext. */
+
+/* Scans all the OomdCGroupContexts in `h` and returns 1 and a set of pointers to those OomdCGroupContexts in `ret`
+ * if any of them have exceeded their supplied memory pressure limits for the `duration` length of time.
+ * `last_hit_mem_pressure_limit` is updated accordingly for each entry when the limit is exceeded, and when it returns
+ * below the limit.
+ * Returns 0 and sets `ret` to an empty set if no entries exceeded limits for `duration`.
+ * Returns -ENOMEM for allocation errors. */
+int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret);
+
+/* Sum up current OomdCGroupContexts' pgscan values and last interval's pgscan values in `h`. Returns true if the
+ * current sum is higher than the last interval's sum (there was some reclaim activity). */
+bool oomd_memory_reclaim(Hashmap *h);
+
+/* Returns true if the amount of swap free is below the percentage of swap specified by `threshold_percent`. */
+bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent);
+
+static inline int compare_pgscan(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) {
+        assert(c1);
+        assert(c2);
+
+        if ((*c1)->pgscan > (*c2)->pgscan)
+                return -1;
+        else if ((*c1)->pgscan < (*c2)->pgscan)
+                return 1;
+        else
+                return 0;
+}
+
+static inline int compare_swap_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) {
+        assert(c1);
+        assert(c2);
+
+        if ((*c1)->swap_usage > (*c2)->swap_usage)
+                return -1;
+        else if ((*c1)->swap_usage < (*c2)->swap_usage)
+                return 1;
+        else
+                return 0;
+}
+
+/* Get an array of OomdCGroupContexts from `h`, qsorted from largest to smallest values according to `compare_func`.
+ * If `prefix` is not NULL, only include OomdCGroupContexts whose paths start with prefix. Otherwise all paths are sorted.
+ * Returns the number of sorted items; negative on error. */
+int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const char *prefix, OomdCGroupContext ***ret);
+
+/* Returns a negative value on error, 0 if no processes were killed, or 1 if processes were killed. */
+int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run);
+
+/* The following oomd_kill_by_* functions return 1 if processes were killed, or negative otherwise. */
+/* If `prefix` is supplied, only cgroups whose paths start with `prefix` are eligible candidates. Otherwise,
+ * everything in `h` is a candidate. */
+int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run);
+int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run);
+
+int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret);
+int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext *ret);
+
+/* Get the OomdCGroupContext of `path` and insert it into `new_h`. The key for the inserted context will be `path`.
+ *
+ * `old_h` is used to get data used to calculate prior interval information. `old_h` can be NULL in which case there
+ * was no prior data to reference. */
+int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path);
+
+void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix);
+void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix);
+void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix);
diff --git a/src/oom/oomd.c b/src/oom/oomd.c
new file mode 100644 (file)
index 0000000..2c0031a
--- /dev/null
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "bus-log-control-api.h"
+#include "bus-object.h"
+#include "cgroup-util.h"
+#include "conf-parser.h"
+#include "daemon-util.h"
+#include "log.h"
+#include "main-func.h"
+#include "oomd-manager.h"
+#include "oomd-manager-bus.h"
+#include "parse-util.h"
+#include "pretty-print.c"
+#include "psi-util.h"
+#include "signal-util.h"
+
+static bool arg_dry_run = false;
+static int arg_swap_used_limit = -1;
+static int arg_mem_pressure_limit = -1;
+
+static int parse_config(void) {
+        static const ConfigTableItem items[] = {
+                { "OOM", "SwapUsedLimitPercent",              config_parse_percent, 0, &arg_swap_used_limit    },
+                { "OOM", "DefaultMemoryPressureLimitPercent", config_parse_percent, 0, &arg_mem_pressure_limit },
+                {}
+        };
+
+        return config_parse_many_nulstr(PKGSYSCONFDIR "/oomd.conf",
+                                        CONF_PATHS_NULSTR("systemd/oomd.conf.d"),
+                                        "OOM\0",
+                                        config_item_table_lookup,
+                                        items,
+                                        CONFIG_PARSE_WARN,
+                                        NULL,
+                                        NULL);
+}
+
+static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("systemd-oomd", "1", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...]\n\n"
+               "Run the userspace out-of-memory (OOM) killer.\n\n"
+               "  -h --help                 Show this help\n"
+               "     --version              Show package version\n"
+               "     --dry-run              Only print destructive actions instead of doing them\n"
+               "     --bus-introspect=PATH  Write D-Bus XML introspection data\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , link
+        );
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_DRY_RUN,
+                ARG_BUS_INTROSPECT,
+        };
+
+        static const struct option options[] = {
+                { "help",           no_argument,       NULL, 'h'                },
+                { "version",        no_argument,       NULL, ARG_VERSION        },
+                { "dry-run",        no_argument,       NULL, ARG_DRY_RUN        },
+                { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
+                switch (c) {
+
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        return version();
+
+                case ARG_DRY_RUN:
+                        arg_dry_run = true;
+                        break;
+
+                case ARG_BUS_INTROSPECT:
+                        return bus_introspect_implementations(
+                                        stdout,
+                                        optarg,
+                                        BUS_IMPLEMENTATIONS(&manager_object,
+                                                            &log_control_object));
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unknown option code.");
+                }
+
+        if (optind < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "This program takes no arguments.");
+
+        return 1;
+}
+
+static int run(int argc, char *argv[]) {
+        _cleanup_(notify_on_cleanup) const char *notify_msg = NULL;
+        _cleanup_(manager_freep) Manager *m = NULL;
+        int r;
+
+        log_setup_service();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r;
+
+        r = parse_config();
+        if (r < 0)
+                return r;
+
+        /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
+         * requirements do not have a reliable means to check for in code. */
+        if (access("/proc/swaps", F_OK) < 0)
+                return log_error_errno(errno, "Swap not enabled: %m");
+
+        if (!is_pressure_supported())
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Pressure Stall Information (PSI) is not supported");
+
+        r = cg_all_unified();
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires the unified cgroups hierarchy");
+
+        assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+
+        r = manager_new(&m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create manager: %m");
+
+        r = manager_start(m, arg_dry_run, arg_swap_used_limit, arg_mem_pressure_limit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to start up daemon: %m");
+
+        notify_msg = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
+
+        log_info("systemd-oomd starting%s!", arg_dry_run ? " in dry run mode" : "");
+
+        r = sd_event_loop(m->event);
+        if (r < 0)
+                return log_error_errno(r, "Event loop failed: %m");
+
+        return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/oom/oomd.conf b/src/oom/oomd.conf
new file mode 100644 (file)
index 0000000..8ac9716
--- /dev/null
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  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.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See oomd.conf(5) for details
+
+[OOM]
+#SwapUsedLimitPercent=90%
+#DefaultMemoryPressureLimitPercent=60%
diff --git a/src/oom/org.freedesktop.oom1.conf b/src/oom/org.freedesktop.oom1.conf
new file mode 100644 (file)
index 0000000..48b526f
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<busconfig>
+
+        <policy user="systemd-oom">
+                <allow own="org.freedesktop.oom1"/>
+                <allow send_destination="org.freedesktop.oom1"/>
+                <allow receive_sender="org.freedesktop.oom1"/>
+        </policy>
+
+        <policy user="root">
+                <allow send_destination="org.freedesktop.oom1"/>
+        </policy>
+
+        <policy context="default">
+                <deny send_destination="org.freedesktop.oom1"/>
+
+                <!-- Generic interfaces -->
+
+                <allow send_destination="org.freedesktop.oom1"
+                       send_interface="org.freedesktop.DBus.Introspectable"/>
+
+                <allow send_destination="org.freedesktop.oom1"
+                       send_interface="org.freedesktop.DBus.Peer"/>
+
+                <allow send_destination="org.freedesktop.oom1"
+                       send_interface="org.freedesktop.DBus.Properties"
+                       send_member="Get"/>
+
+                <allow send_destination="org.freedesktop.oom1"
+                       send_interface="org.freedesktop.DBus.Properties"
+                       send_member="GetAll"/>
+
+                <!-- Manager interface -->
+
+                <allow send_destination="org.freedesktop.oom1"
+                       send_interface="org.freedesktop.oom1.Manager"
+                       send_member="DumpByFileDescriptor"/>
+
+                <allow receive_sender="org.freedesktop.oom1"/>
+        </policy>
+
+</busconfig>
diff --git a/src/oom/org.freedesktop.oom1.service b/src/oom/org.freedesktop.oom1.service
new file mode 100644 (file)
index 0000000..7815071
--- /dev/null
@@ -0,0 +1,14 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[D-BUS Service]
+Name=org.freedesktop.oom1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.oom1.service
diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c
new file mode 100644 (file)
index 0000000..38cae9e
--- /dev/null
@@ -0,0 +1,350 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "cgroup-setup.h"
+#include "cgroup-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "oomd-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tests.h"
+
+static int fork_and_sleep(unsigned sleep_min) {
+        usec_t n, timeout, ts;
+
+        pid_t pid = fork();
+        assert_se(pid >= 0);
+
+        if (pid == 0) {
+                timeout = sleep_min * USEC_PER_MINUTE;
+                ts = now(CLOCK_MONOTONIC);
+                while (true) {
+                        n = now(CLOCK_MONOTONIC);
+                        if (ts + timeout < n) {
+                                log_error("Child timed out waiting to be killed");
+                                abort();
+                        }
+                        sleep(1);
+                }
+        }
+
+        return pid;
+}
+
+static void test_oomd_cgroup_kill(void) {
+        _cleanup_free_ char *cgroup_root = NULL, *cgroup = NULL;
+        int pid[2];
+        int r;
+
+        if (geteuid() != 0)
+                return (void) log_tests_skipped("not root");
+
+        if (cg_all_unified() <= 0)
+                return (void) log_tests_skipped("cgroups are not running in unified mode");
+
+        assert_se(cg_pid_get_path(NULL, 0, &cgroup_root) >= 0);
+
+        /* Create another cgroup below this one for the pids we forked off. We need this to be managed
+         * by the test so that pid1 doesn't delete it before we can read the xattrs. */
+        cgroup = path_join(cgroup_root, "oomdkilltest");
+        assert(cgroup);
+        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, cgroup) >= 0);
+
+        /* If we don't have permissions to set xattrs we're likely in a userns or missing capabilities */
+        r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_test", "test", 4, 0);
+        if (IN_SET(r, -EPERM, -ENOTSUP))
+                return (void) log_tests_skipped("Cannot set user xattrs");
+
+        /* Do this twice to also check the increment behavior on the xattrs */
+        for (int i = 0; i < 2; i++) {
+                _cleanup_free_ char *v = NULL;
+
+                for (int j = 0; j < 2; j++) {
+                        pid[j] = fork_and_sleep(5);
+                        assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup, pid[j]) >= 0);
+                }
+
+                r = oomd_cgroup_kill(cgroup, false /* recurse */, false /* dry run */);
+                if (r <= 0) {
+                        log_debug_errno(r, "Failed to kill processes under %s: %m", cgroup);
+                        abort();
+                }
+
+                /* Wait a bit since processes may take some time to be cleaned up. */
+                sleep(2);
+                assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, cgroup) == true);
+
+                assert_se(cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.systemd_oomd_kill", &v) >= 0);
+                assert_se(memcmp(v, i == 0 ? "2" : "4", 2) == 0);
+        }
+}
+
+static void test_oomd_cgroup_context_acquire_and_insert(void) {
+        _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
+        _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL;
+        _cleanup_free_ char *cgroup = NULL;
+        OomdCGroupContext *c1, *c2;
+
+        if (geteuid() != 0)
+                return (void) log_tests_skipped("not root");
+
+        if (!is_pressure_supported())
+                return (void) log_tests_skipped("system does not support pressure");
+
+        if (cg_all_unified() <= 0)
+                return (void) log_tests_skipped("cgroups are not running in unified mode");
+
+        assert_se(cg_pid_get_path(NULL, 0, &cgroup) >= 0);
+
+        assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
+
+        assert_se(streq(ctx->path, cgroup));
+        assert_se(ctx->memory_pressure.avg10 == 0);
+        assert_se(ctx->memory_pressure.avg60 == 0);
+        assert_se(ctx->memory_pressure.avg300 == 0);
+        assert_se(ctx->memory_pressure.total == 0);
+        assert_se(ctx->current_memory_usage > 0);
+        assert_se(ctx->memory_min == 0);
+        assert_se(ctx->memory_low == 0);
+        assert_se(ctx->swap_usage == 0);
+        assert_se(ctx->last_pgscan == 0);
+        assert_se(ctx->pgscan == 0);
+        ctx = oomd_cgroup_context_free(ctx);
+
+        /* Test the root cgroup */
+        assert_se(oomd_cgroup_context_acquire("", &ctx) == 0);
+        assert_se(streq(ctx->path, "/"));
+        assert_se(ctx->current_memory_usage > 0);
+
+        /* Test hashmap inserts */
+        assert_se(h1 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
+        assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == 0);
+        c1 = hashmap_get(h1, cgroup);
+        assert_se(c1);
+
+         /* make sure certain values from h1 get updated in h2 */
+        c1->pgscan = 5555;
+        c1->mem_pressure_limit = 6789;
+        c1->last_hit_mem_pressure_limit = 42;
+        assert_se(h2 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
+        assert_se(oomd_insert_cgroup_context(h1, h2, cgroup) == 0);
+        c1 = hashmap_get(h1, cgroup);
+        c2 = hashmap_get(h2, cgroup);
+        assert_se(c1);
+        assert_se(c2);
+        assert_se(c1 != c2);
+        assert_se(c2->last_pgscan == 5555);
+        assert_se(c2->mem_pressure_limit == 6789);
+        assert_se(c2->last_hit_mem_pressure_limit == 42);
+}
+
+static void test_oomd_system_context_acquire(void) {
+        _cleanup_(unlink_tempfilep) char path[] = "/oomdgetsysctxtestXXXXXX";
+        OomdSystemContext ctx;
+
+        if (geteuid() != 0)
+                return (void) log_tests_skipped("not root");
+
+        assert_se(mkstemp(path));
+
+        assert_se(oomd_system_context_acquire("/verylikelynonexistentpath", &ctx) == -ENOENT);
+
+        assert_se(oomd_system_context_acquire(path, &ctx) == 0);
+        assert_se(ctx.swap_total == 0);
+        assert_se(ctx.swap_used == 0);
+
+        assert_se(write_string_file(path, "some\nwords\nacross\nmultiple\nlines", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(oomd_system_context_acquire(path, &ctx) == 0);
+        assert_se(ctx.swap_total == 0);
+        assert_se(ctx.swap_used == 0);
+
+        assert_se(write_string_file(path, "Filename                                Type            Size    Used    Priority\n"
+                                          "/swapvol/swapfile                       file            18971644        0       -3\n"
+                                          "/dev/vda2                               partition       1999868 993780  -2", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(oomd_system_context_acquire(path, &ctx) == 0);
+        assert_se(ctx.swap_total == 21474828288);
+        assert_se(ctx.swap_used == 1017630720);
+}
+
+static void test_oomd_pressure_above(void) {
+        _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
+        _cleanup_set_free_ Set *t1 = NULL, *t2 = NULL, *t3 = NULL;
+        OomdCGroupContext ctx[2], *c;
+        loadavg_t threshold;
+
+        assert_se(store_loadavg_fixed_point(80, 0, &threshold) == 0);
+
+        /* /herp.slice */
+        assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg10)) == 0);
+        assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg60)) == 0);
+        assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg300)) == 0);
+        ctx[0].mem_pressure_limit = threshold;
+
+        /* /derp.slice */
+        assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg10)) == 0);
+        assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg60)) == 0);
+        assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg300)) == 0);
+        ctx[1].mem_pressure_limit = threshold;
+
+
+        /* High memory pressure */
+        assert_se(h1 = hashmap_new(&string_hash_ops));
+        assert_se(hashmap_put(h1, "/herp.slice", &ctx[0]) >= 0);
+        assert_se(oomd_pressure_above(h1, 0 /* duration */, &t1) == 1);
+        assert_se(set_contains(t1, &ctx[0]) == true);
+        assert_se(c = hashmap_get(h1, "/herp.slice"));
+        assert_se(c->last_hit_mem_pressure_limit > 0);
+
+        /* Low memory pressure */
+        assert_se(h2 = hashmap_new(&string_hash_ops));
+        assert_se(hashmap_put(h2, "/derp.slice", &ctx[1]) >= 0);
+        assert_se(oomd_pressure_above(h2, 0 /* duration */, &t2) == 0);
+        assert_se(t2 == NULL);
+        assert_se(c = hashmap_get(h2, "/derp.slice"));
+        assert_se(c->last_hit_mem_pressure_limit == 0);
+
+        /* High memory pressure w/ multiple cgroups */
+        assert_se(hashmap_put(h1, "/derp.slice", &ctx[1]) >= 0);
+        assert_se(oomd_pressure_above(h1, 0 /* duration */, &t3) == 1);
+        assert_se(set_contains(t3, &ctx[0]) == true);
+        assert_se(set_size(t3) == 1);
+        assert_se(c = hashmap_get(h1, "/herp.slice"));
+        assert_se(c->last_hit_mem_pressure_limit > 0);
+        assert_se(c = hashmap_get(h1, "/derp.slice"));
+        assert_se(c->last_hit_mem_pressure_limit == 0);
+}
+
+static void test_oomd_memory_reclaim(void) {
+        _cleanup_hashmap_free_ Hashmap *h1 = NULL;
+        char **paths = STRV_MAKE("/0.slice",
+                                 "/1.slice",
+                                 "/2.slice",
+                                 "/3.slice",
+                                 "/4.slice");
+
+        OomdCGroupContext ctx[5] = {
+                { .path = paths[0],
+                  .last_pgscan = 100,
+                  .pgscan = 100 },
+                { .path = paths[1],
+                  .last_pgscan = 100,
+                  .pgscan = 100 },
+                { .path = paths[2],
+                  .last_pgscan = 77,
+                  .pgscan = 33 },
+                { .path = paths[3],
+                  .last_pgscan = UINT64_MAX,
+                  .pgscan = 100 },
+                { .path = paths[4],
+                  .last_pgscan = 100,
+                  .pgscan = UINT64_MAX },
+        };
+
+        assert_se(h1 = hashmap_new(&string_hash_ops));
+        assert_se(hashmap_put(h1, paths[0], &ctx[0]) >= 0);
+        assert_se(hashmap_put(h1, paths[1], &ctx[1]) >= 0);
+        assert_se(oomd_memory_reclaim(h1) == false);
+
+        assert_se(hashmap_put(h1, paths[2], &ctx[2]) >= 0);
+        assert_se(oomd_memory_reclaim(h1) == false);
+
+        assert_se(hashmap_put(h1, paths[4], &ctx[4]) >= 0);
+        assert_se(oomd_memory_reclaim(h1) == true);
+
+        assert_se(hashmap_put(h1, paths[3], &ctx[3]) >= 0);
+        assert_se(oomd_memory_reclaim(h1) == false);
+}
+
+static void test_oomd_swap_free_below(void) {
+        OomdSystemContext ctx = (OomdSystemContext) {
+                .swap_total = 20971512 * 1024U,
+                .swap_used = 20971440 * 1024U,
+        };
+        assert_se(oomd_swap_free_below(&ctx, 20) == true);
+
+        ctx = (OomdSystemContext) {
+                .swap_total = 20971512 * 1024U,
+                .swap_used = 3310136 * 1024U,
+        };
+        assert_se(oomd_swap_free_below(&ctx, 20) == false);
+}
+
+static void test_oomd_sort_cgroups(void) {
+        _cleanup_hashmap_free_ Hashmap *h = NULL;
+        _cleanup_free_ OomdCGroupContext **sorted_cgroups;
+        char **paths = STRV_MAKE("/herp.slice",
+                                 "/herp.slice/derp.scope",
+                                 "/herp.slice/derp.scope/sheep.service",
+                                 "/zupa.slice");
+
+        OomdCGroupContext ctx[4] = {
+                { .path = paths[0],
+                  .swap_usage = 20,
+                  .pgscan = 60 },
+                { .path = paths[1],
+                  .swap_usage = 60,
+                  .pgscan = 40 },
+                { .path = paths[2],
+                  .swap_usage = 40,
+                  .pgscan = 20 },
+                { .path = paths[3],
+                  .swap_usage = 10,
+                  .pgscan = 80 },
+        };
+
+        assert_se(h = hashmap_new(&string_hash_ops));
+
+        assert_se(hashmap_put(h, "/herp.slice", &ctx[0]) >= 0);
+        assert_se(hashmap_put(h, "/herp.slice/derp.scope", &ctx[1]) >= 0);
+        assert_se(hashmap_put(h, "/herp.slice/derp.scope/sheep.service", &ctx[2]) >= 0);
+        assert_se(hashmap_put(h, "/zupa.slice", &ctx[3]) >= 0);
+
+        assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 4);
+        assert_se(sorted_cgroups[0] == &ctx[1]);
+        assert_se(sorted_cgroups[1] == &ctx[2]);
+        assert_se(sorted_cgroups[2] == &ctx[0]);
+        assert_se(sorted_cgroups[3] == &ctx[3]);
+        sorted_cgroups = mfree(sorted_cgroups);
+
+        assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan, NULL, &sorted_cgroups) == 4);
+        assert_se(sorted_cgroups[0] == &ctx[3]);
+        assert_se(sorted_cgroups[1] == &ctx[0]);
+        assert_se(sorted_cgroups[2] == &ctx[1]);
+        assert_se(sorted_cgroups[3] == &ctx[2]);
+        sorted_cgroups = mfree(sorted_cgroups);
+
+        assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan, "/herp.slice/derp.scope", &sorted_cgroups) == 2);
+        assert_se(sorted_cgroups[0] == &ctx[1]);
+        assert_se(sorted_cgroups[1] == &ctx[2]);
+        assert_se(sorted_cgroups[2] == 0);
+        assert_se(sorted_cgroups[3] == 0);
+        sorted_cgroups = mfree(sorted_cgroups);
+}
+
+int main(void) {
+        int r;
+
+        test_setup_logging(LOG_DEBUG);
+
+        test_oomd_system_context_acquire();
+        test_oomd_pressure_above();
+        test_oomd_memory_reclaim();
+        test_oomd_swap_free_below();
+        test_oomd_sort_cgroups();
+
+        /* The following tests operate on live cgroups */
+
+        r = enter_cgroup_root(NULL);
+        if (r < 0)
+                return log_tests_skipped_errno(r, "failed to enter a test cgroup scope");
+
+        test_oomd_cgroup_kill();
+        test_oomd_cgroup_context_acquire_and_insert();
+
+        return 0;
+}
index d406c9dbe3ed0d5a15955c8c9f8f4798e5f235cf..4cf6a5fe3a69e447557b028c7f2fcf57c48d9fda 100644 (file)
@@ -3245,7 +3245,7 @@ static int context_read_seed(Context *context, const char *root) {
                 else if (fd < 0)
                         return log_error_errno(fd, "Failed to determine machine ID of image: %m");
                 else {
-                        r = id128_read_fd(fd, ID128_PLAIN, &context->seed);
+                        r = id128_read_fd(fd, ID128_PLAIN_OR_UNINIT, &context->seed);
                         if (r == -ENOMEDIUM)
                                 log_info("No machine ID set, using randomized partition UUIDs.");
                         else if (r < 0)
index 5765978290c91d9ecdddc4f1c61d1081629ab19f..9af3049b6b2db5c40e57708c6039b59d8daa9b8a 100755 (executable)
@@ -6,7 +6,7 @@ set -ex
 repart=$1
 test -x $repart
 
-D=$(mktemp --directory)
+D=$(mktemp --tmpdir --directory "test-repart.XXXXXXXXXX")
 trap "rm -rf '$D'" EXIT INT QUIT PIPE
 mkdir -p $D/definitions
 
index d74331df3ea771f35c4676acb6aec0ced8f35b22..55ea6759e912d08ffbc47c7e996fb1bbe7cdcc28 100644 (file)
@@ -434,10 +434,9 @@ static int portable_extract_by_path(
                         if (isempty(name) && fd < 0)
                                 break;
 
-                        if (isempty(name) || fd < 0) {
-                                log_debug("Invalid item sent from child.");
-                                return -EINVAL;
-                        }
+                        if (isempty(name) || fd < 0)
+                                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid item sent from child.");
 
                         add = portable_metadata_new(name, fd);
                         if (!add)
index 4369dfd1563b8acbff9961735741aedda65cdd87..7a4f60163e15795e544df7924eb7fb06f2210163 100644 (file)
@@ -178,7 +178,7 @@ static int acquire_bus(sd_bus **bus) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to bus: %m");
+                return bus_log_connect_error(r);
 
         (void) sd_bus_set_allow_interactive_authorization(*bus, arg_ask_password);
 
index da2256f5ccba54a6cf3966236da261551fca049a..a145117efd129d366aff4672c4e84f1839cb585e 100644 (file)
@@ -142,7 +142,7 @@ libsystemd_resolve_core = static_library(
 
 systemd_resolved_sources += [resolved_gperf_c, resolved_dnssd_gperf_c]
 
-systemd_resolved_dependencies = [threads, libgpg_error, libm, libidn]
+systemd_resolved_dependencies = [threads, libgpg_error, libm]
 if conf.get('ENABLE_DNS_OVER_TLS') == 1
         if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
                 systemd_resolved_sources += files('resolved-dnstls-gnutls.c',
index dc5ac05532abceb358567da9a6f778be557d3fc0..b4e9a96b35a122832e997a09d64d5923cfe74ddd 100644 (file)
@@ -16,3 +16,4 @@
 
 nameserver 127.0.0.53
 options edns0 trust-ad
+search .
index 8378ff591c766360b8c01d89fd7317a95eb995b4..a2c5dcb41842a501e5f78abc0e875c53b58a7bf4 100644 (file)
@@ -35,6 +35,7 @@
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "utf8.h"
 #include "verbs.h"
 
 static int arg_family = AF_UNSPEC;
@@ -261,10 +262,9 @@ static int resolve_host(sd_bus *bus, const char *name) {
                        (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
                        canonical);
 
-        if (c == 0) {
-                log_error("%s: no addresses found", name);
-                return -ESRCH;
-        }
+        if (c == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
+                                       "%s: no addresses found", name);
 
         print_source(flags, ts);
 
@@ -356,10 +356,9 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        if (c == 0) {
-                log_error("%s: no names found", pretty);
-                return -ESRCH;
-        }
+        if (c == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
+                                       "%s: no names found", pretty);
 
         print_source(flags, ts);
 
@@ -1298,24 +1297,46 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m,
         if (r < 0)
                 return r;
 
+        strv_sort(*l);
+
         return 0;
 }
 
 static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
+        const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */
+        int pos1, pos2;
+
+        if (ifname)
+                printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal());
+        else
+                printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
+
+        size_t cols = columns(), position = pos2 - pos1 + 2;
         char **i;
 
-        printf("%sLink %i (%s)%s:",
-               ansi_highlight(), ifindex, ifname, ansi_normal());
+        STRV_FOREACH(i, p) {
+                size_t our_len = utf8_console_width(*i); /* This returns -1 on invalid utf-8 (which shouldn't happen).
+                                                          * If that happens, we'll just print one item per line. */
 
-        STRV_FOREACH(i, p)
-                printf(" %s", *i);
+                if (position <= indent || size_add(size_add(position, 1), our_len) < cols) {
+                        printf(" %s", *i);
+                        position = size_add(size_add(position, 1), our_len);
+                } else {
+                        printf("\n%*s%s", indent, "", *i);
+                        position = size_add(our_len, indent);
+                }
+        }
 
         printf("\n");
 
         return 0;
 }
 
-struct link_info {
+static int status_print_strv_global(char **p) {
+        return status_print_strv_ifindex(0, NULL, p);
+}
+
+typedef struct LinkInfo {
         uint64_t scopes_mask;
         const char *llmnr;
         const char *mdns;
@@ -1329,9 +1350,26 @@ struct link_info {
         char **ntas;
         bool dnssec_supported;
         bool default_route;
-};
+} LinkInfo;
 
-static void link_info_clear(struct link_info *p) {
+typedef struct GlobalInfo {
+        char *current_dns;
+        char *current_dns_ex;
+        char **dns;
+        char **dns_ex;
+        char **fallback_dns;
+        char **fallback_dns_ex;
+        char **domains;
+        char **ntas;
+        const char *llmnr;
+        const char *mdns;
+        const char *dns_over_tls;
+        const char *dnssec;
+        const char *resolv_conf_mode;
+        bool dnssec_supported;
+} GlobalInfo;
+
+static void link_info_clear(LinkInfo *p) {
         free(p->current_dns);
         free(p->current_dns_ex);
         strv_free(p->dns);
@@ -1340,6 +1378,17 @@ static void link_info_clear(struct link_info *p) {
         strv_free(p->ntas);
 }
 
+static void global_info_clear(GlobalInfo *p) {
+        free(p->current_dns);
+        free(p->current_dns_ex);
+        strv_free(p->dns);
+        strv_free(p->dns_ex);
+        strv_free(p->fallback_dns);
+        strv_free(p->fallback_dns_ex);
+        strv_free(p->domains);
+        strv_free(p->ntas);
+}
+
 static int dump_list(Table *table, const char *prefix, char * const *l) {
         int r;
 
@@ -1348,33 +1397,88 @@ static int dump_list(Table *table, const char *prefix, char * const *l) {
 
         r = table_add_many(table,
                            TABLE_STRING, prefix,
-                           TABLE_STRV, l);
+                           TABLE_STRV_WRAPPED, l);
         if (r < 0)
                 return table_log_add_error(r);
 
         return 0;
 }
 
+static int strv_extend_extended_bool(char ***strv, const char *name, const char *value) {
+        int r;
+
+        if (value) {
+                r = parse_boolean(value);
+                if (r >= 0)
+                        return strv_extendf(strv, "%s%s", plus_minus(r), name);
+        }
+
+        return strv_extendf(strv, "%s=%s", name, value ?: "???");
+}
+
+static char** link_protocol_status(const LinkInfo *info) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (strv_extendf(&s, "%sDefaultRoute", plus_minus(info->default_route)) < 0)
+                return NULL;
+
+        if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
+                return NULL;
+
+        if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
+                return NULL;
+
+        if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
+                return NULL;
+
+        if (strv_extendf(&s, "DNSSEC=%s/%s",
+                         info->dnssec ?: "???",
+                         info->dnssec_supported ? "supported" : "unsupported") < 0)
+                return NULL;
+
+        return TAKE_PTR(s);
+}
+
+static char** global_protocol_status(const GlobalInfo *info) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
+                return NULL;
+
+        if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
+                return NULL;
+
+        if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
+                return NULL;
+
+        if (strv_extendf(&s, "DNSSEC=%s/%s",
+                         info->dnssec ?: "???",
+                         info->dnssec_supported ? "supported" : "unsupported") < 0)
+                return NULL;
+
+        return TAKE_PTR(s);
+}
+
 static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
         static const struct bus_properties_map property_map[] = {
-                { "ScopesMask",                 "t",        NULL,                           offsetof(struct link_info, scopes_mask)      },
-                { "DNS",                        "a(iay)",   map_link_dns_servers,           offsetof(struct link_info, dns)              },
-                { "DNSEx",                      "a(iayqs)", map_link_dns_servers_ex,        offsetof(struct link_info, dns_ex)           },
-                { "CurrentDNSServer",           "(iay)",    map_link_current_dns_server,    offsetof(struct link_info, current_dns)      },
-                { "CurrentDNSServerEx",         "(iayqs)",  map_link_current_dns_server_ex, offsetof(struct link_info, current_dns_ex)   },
-                { "Domains",                    "a(sb)",    map_link_domains,               offsetof(struct link_info, domains)          },
-                { "DefaultRoute",               "b",        NULL,                           offsetof(struct link_info, default_route)    },
-                { "LLMNR",                      "s",        NULL,                           offsetof(struct link_info, llmnr)            },
-                { "MulticastDNS",               "s",        NULL,                           offsetof(struct link_info, mdns)             },
-                { "DNSOverTLS",                 "s",        NULL,                           offsetof(struct link_info, dns_over_tls)     },
-                { "DNSSEC",                     "s",        NULL,                           offsetof(struct link_info, dnssec)           },
-                { "DNSSECNegativeTrustAnchors", "as",       NULL,                           offsetof(struct link_info, ntas)             },
-                { "DNSSECSupported",            "b",        NULL,                           offsetof(struct link_info, dnssec_supported) },
+                { "ScopesMask",                 "t",        NULL,                           offsetof(LinkInfo, scopes_mask)      },
+                { "DNS",                        "a(iay)",   map_link_dns_servers,           offsetof(LinkInfo, dns)              },
+                { "DNSEx",                      "a(iayqs)", map_link_dns_servers_ex,        offsetof(LinkInfo, dns_ex)           },
+                { "CurrentDNSServer",           "(iay)",    map_link_current_dns_server,    offsetof(LinkInfo, current_dns)      },
+                { "CurrentDNSServerEx",         "(iayqs)",  map_link_current_dns_server_ex, offsetof(LinkInfo, current_dns_ex)   },
+                { "Domains",                    "a(sb)",    map_link_domains,               offsetof(LinkInfo, domains)          },
+                { "DefaultRoute",               "b",        NULL,                           offsetof(LinkInfo, default_route)    },
+                { "LLMNR",                      "s",        NULL,                           offsetof(LinkInfo, llmnr)            },
+                { "MulticastDNS",               "s",        NULL,                           offsetof(LinkInfo, mdns)             },
+                { "DNSOverTLS",                 "s",        NULL,                           offsetof(LinkInfo, dns_over_tls)     },
+                { "DNSSEC",                     "s",        NULL,                           offsetof(LinkInfo, dnssec)           },
+                { "DNSSECNegativeTrustAnchors", "as",       bus_map_strv_sort,              offsetof(LinkInfo, ntas)             },
+                { "DNSSECSupported",            "b",        NULL,                           offsetof(LinkInfo, dnssec_supported) },
                 {}
         };
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_(link_info_clear) struct link_info link_info = {};
+        _cleanup_(link_info_clear) LinkInfo link_info = {};
         _cleanup_(table_unrefp) Table *table = NULL;
         _cleanup_free_ char *p = NULL;
         char ifi[DECIMAL_STR_MAX(int)], ifname[IF_NAMESIZE + 1] = "";
@@ -1498,19 +1602,13 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
         if (r < 0)
                 return table_log_add_error(r);
 
+        _cleanup_strv_free_ char **pstatus = link_protocol_status(&link_info);
+        if (!pstatus)
+                return log_oom();
+
         r = table_add_many(table,
-                           TABLE_STRING, "DefaultRoute setting:",
-                           TABLE_BOOLEAN, link_info.default_route,
-                           TABLE_STRING, "LLMNR setting:",
-                           TABLE_STRING, strna(link_info.llmnr),
-                           TABLE_STRING, "MulticastDNS setting:",
-                           TABLE_STRING, strna(link_info.mdns),
-                           TABLE_STRING, "DNSOverTLS setting:",
-                           TABLE_STRING, strna(link_info.dns_over_tls),
-                           TABLE_STRING, "DNSSEC setting:",
-                           TABLE_STRING, strna(link_info.dnssec),
-                           TABLE_STRING, "DNSSEC supported:",
-                           TABLE_BOOLEAN, link_info.dnssec_supported);
+                           TABLE_STRING,       "Protocols:",
+                           TABLE_STRV_WRAPPED, pstatus);
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -1633,69 +1731,32 @@ static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m
         if (r < 0)
                 return r;
 
-        return 0;
-}
-
-static int status_print_strv_global(char **p) {
-        char **i;
-
-        printf("%sGlobal%s:", ansi_highlight(), ansi_normal());
-
-        STRV_FOREACH(i, p)
-                printf(" %s", *i);
-
-        printf("\n");
+        strv_sort(*l);
 
         return 0;
 }
 
-struct global_info {
-        char *current_dns;
-        char *current_dns_ex;
-        char **dns;
-        char **dns_ex;
-        char **fallback_dns;
-        char **fallback_dns_ex;
-        char **domains;
-        char **ntas;
-        const char *llmnr;
-        const char *mdns;
-        const char *dns_over_tls;
-        const char *dnssec;
-        bool dnssec_supported;
-};
-
-static void global_info_clear(struct global_info *p) {
-        free(p->current_dns);
-        free(p->current_dns_ex);
-        strv_free(p->dns);
-        strv_free(p->dns_ex);
-        strv_free(p->fallback_dns);
-        strv_free(p->fallback_dns_ex);
-        strv_free(p->domains);
-        strv_free(p->ntas);
-}
-
 static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
         static const struct bus_properties_map property_map[] = {
-                { "DNS",                        "a(iiay)",   map_global_dns_servers,           offsetof(struct global_info, dns)              },
-                { "DNSEx",                      "a(iiayqs)", map_global_dns_servers_ex,        offsetof(struct global_info, dns_ex)           },
-                { "FallbackDNS",                "a(iiay)",   map_global_dns_servers,           offsetof(struct global_info, fallback_dns)     },
-                { "FallbackDNSEx",              "a(iiayqs)", map_global_dns_servers_ex,        offsetof(struct global_info, fallback_dns_ex)  },
-                { "CurrentDNSServer",           "(iiay)",    map_global_current_dns_server,    offsetof(struct global_info, current_dns)      },
-                { "CurrentDNSServerEx",         "(iiayqs)",  map_global_current_dns_server_ex, offsetof(struct global_info, current_dns_ex)   },
-                { "Domains",                    "a(isb)",    map_global_domains,               offsetof(struct global_info, domains)          },
-                { "DNSSECNegativeTrustAnchors", "as",        NULL,                             offsetof(struct global_info, ntas)             },
-                { "LLMNR",                      "s",         NULL,                             offsetof(struct global_info, llmnr)            },
-                { "MulticastDNS",               "s",         NULL,                             offsetof(struct global_info, mdns)             },
-                { "DNSOverTLS",                 "s",         NULL,                             offsetof(struct global_info, dns_over_tls)     },
-                { "DNSSEC",                     "s",         NULL,                             offsetof(struct global_info, dnssec)           },
-                { "DNSSECSupported",            "b",         NULL,                             offsetof(struct global_info, dnssec_supported) },
+                { "DNS",                        "a(iiay)",   map_global_dns_servers,           offsetof(GlobalInfo, dns)              },
+                { "DNSEx",                      "a(iiayqs)", map_global_dns_servers_ex,        offsetof(GlobalInfo, dns_ex)           },
+                { "FallbackDNS",                "a(iiay)",   map_global_dns_servers,           offsetof(GlobalInfo, fallback_dns)     },
+                { "FallbackDNSEx",              "a(iiayqs)", map_global_dns_servers_ex,        offsetof(GlobalInfo, fallback_dns_ex)  },
+                { "CurrentDNSServer",           "(iiay)",    map_global_current_dns_server,    offsetof(GlobalInfo, current_dns)      },
+                { "CurrentDNSServerEx",         "(iiayqs)",  map_global_current_dns_server_ex, offsetof(GlobalInfo, current_dns_ex)   },
+                { "Domains",                    "a(isb)",    map_global_domains,               offsetof(GlobalInfo, domains)          },
+                { "DNSSECNegativeTrustAnchors", "as",        bus_map_strv_sort,                offsetof(GlobalInfo, ntas)             },
+                { "LLMNR",                      "s",         NULL,                             offsetof(GlobalInfo, llmnr)            },
+                { "MulticastDNS",               "s",         NULL,                             offsetof(GlobalInfo, mdns)             },
+                { "DNSOverTLS",                 "s",         NULL,                             offsetof(GlobalInfo, dns_over_tls)     },
+                { "DNSSEC",                     "s",         NULL,                             offsetof(GlobalInfo, dnssec)           },
+                { "DNSSECSupported",            "b",         NULL,                             offsetof(GlobalInfo, dnssec_supported) },
+                { "ResolvConfMode",             "s",         NULL,                             offsetof(GlobalInfo, resolv_conf_mode) },
                 {}
         };
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_(global_info_clear) struct global_info global_info = {};
+        _cleanup_(global_info_clear) GlobalInfo global_info = {};
         _cleanup_(table_unrefp) Table *table = NULL;
         int r;
 
@@ -1760,21 +1821,25 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
 
         table_set_header(table, false);
 
+        _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info);
+        if (!pstatus)
+                return log_oom();
+
         r = table_add_many(table,
-                           TABLE_STRING, "LLMNR setting:",
+                           TABLE_STRING,            "Protocols:",
                            TABLE_SET_ALIGN_PERCENT, 100,
-                           TABLE_STRING, strna(global_info.llmnr),
-                           TABLE_STRING, "MulticastDNS setting:",
-                           TABLE_STRING, strna(global_info.mdns),
-                           TABLE_STRING, "DNSOverTLS setting:",
-                           TABLE_STRING, strna(global_info.dns_over_tls),
-                           TABLE_STRING, "DNSSEC setting:",
-                           TABLE_STRING, strna(global_info.dnssec),
-                           TABLE_STRING, "DNSSEC supported:",
-                           TABLE_BOOLEAN, global_info.dnssec_supported);
+                           TABLE_STRV_WRAPPED,      pstatus);
         if (r < 0)
                 return table_log_add_error(r);
 
+        if (global_info.resolv_conf_mode) {
+                r = table_add_many(table,
+                                   TABLE_STRING, "resolv.conf mode:",
+                                   TABLE_STRING, global_info.resolv_conf_mode);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
         if (global_info.current_dns) {
                 r = table_add_many(table,
                                    TABLE_STRING, "Current DNS Server:",
@@ -2040,10 +2105,10 @@ static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd
                         r = dns_name_is_valid(n);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
-                        if (r == 0) {
-                                log_error("Domain not valid: %s", n);
-                                return -EINVAL;
-                        }
+                        if (r == 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Domain not valid: %s",
+                                                       n);
 
                         r = sd_bus_message_append(req, "(sb)", n, **p == '~');
                         if (r < 0)
@@ -2338,10 +2403,10 @@ static int verb_nta(int argc, char **argv, void *userdata) {
                         r = dns_name_is_valid(*p);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to validate specified domain %s: %m", *p);
-                        if (r == 0) {
-                                log_error("Domain not valid: %s", *p);
-                                return -EINVAL;
-                        }
+                        if (r == 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Domain not valid: %s",
+                                                       *p);
                 }
 
         r = call_nta(bus, clear ? NULL : argv + 2, bus_resolve_mgr, &error);
index b60a0fd1f24f0f3ffbe54e22b187d84877577c7e..724c3d4a6a10dbe25d7da09a613bfb94024ebc6e 100644 (file)
@@ -15,6 +15,7 @@
 #include "resolved-dnssd-bus.h"
 #include "resolved-dnssd.h"
 #include "resolved-link-bus.h"
+#include "resolved-resolv-conf.h"
 #include "socket-netlink.h"
 #include "stdio-util.h"
 #include "strv.h"
@@ -260,7 +261,12 @@ finish:
         dns_query_free(q);
 }
 
-static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
+static int validate_and_mangle_flags(
+                const char *name,
+                uint64_t *flags,
+                uint64_t ok,
+                sd_bus_error *error) {
+
         assert(flags);
 
         /* Checks that the client supplied interface index and flags parameter actually are valid and make
@@ -277,15 +283,16 @@ static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, u
          *    to mean "all supported protocols".
          */
 
-        if (ifindex < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
-
         if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
 
         if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
                 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
 
+        /* Imply SD_RESOLVED_NO_SEARCH if permitted and name is dot suffixed. */
+        if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0)
+                *flags |= SD_RESOLVED_NO_SEARCH;
+
         return 0;
 }
 
@@ -371,10 +378,13 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
         if (r < 0)
                 return r;
 
+        if (ifindex < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
 
-        r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
+        r = validate_and_mangle_flags(hostname, &flags, SD_RESOLVED_NO_SEARCH, error);
         if (r < 0)
                 return r;
 
@@ -527,7 +537,10 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
         if (r < 0)
                 return r;
 
-        r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
+        if (ifindex < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
+        r = validate_and_mangle_flags(NULL, &flags, 0, error);
         if (r < 0)
                 return r;
 
@@ -679,6 +692,9 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
         if (r < 0)
                 return r;
 
+        if (ifindex < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
         r = dns_name_is_valid(name);
         if (r < 0)
                 return r;
@@ -692,7 +708,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
         if (dns_type_is_obsolete(type))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
 
-        r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
+        r = validate_and_mangle_flags(name, &flags, 0, error);
         if (r < 0)
                 return r;
 
@@ -1205,6 +1221,9 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
         if (r < 0)
                 return r;
 
+        if (ifindex < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
 
@@ -1227,7 +1246,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
         if (name && !type)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
 
-        r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
+        r = validate_and_mangle_flags(name, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
         if (r < 0)
                 return r;
 
@@ -1602,6 +1621,28 @@ static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager,
 static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
 static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dns_over_tls_mode, "s", Manager, manager_get_dns_over_tls_mode, dns_over_tls_mode_to_string);
 
+static int bus_property_get_resolv_conf_mode(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int r;
+
+        assert(reply);
+
+        r = resolv_conf_mode();
+        if (r < 0) {
+                log_warning_errno(r, "Failed to test /etc/resolv.conf mode, ignoring: %m");
+                return sd_bus_message_append(reply, "s", NULL);
+        }
+
+        return sd_bus_message_append(reply, "s", resolv_conf_mode_to_string(r));
+}
+
 static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         DnsScope *s;
@@ -1982,6 +2023,7 @@ static const sd_bus_vtable resolve_vtable[] = {
         SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
         SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
         SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
+        SD_BUS_PROPERTY("ResolvConfMode", "s", bus_property_get_resolv_conf_mode, 0, 0),
 
         SD_BUS_METHOD_WITH_ARGS("ResolveHostname",
                                 SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags),
index 75c8bf315ebce44db3687a5eb4be87afda4e8bb6..62240399925709b174aad3780c9e9bcdb4127ef2 100644 (file)
@@ -689,7 +689,14 @@ fail:
 }
 
 /* Append the OPT pseudo-RR described in RFC6891 */
-int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start) {
+int dns_packet_append_opt(
+                DnsPacket *p,
+                uint16_t max_udp_size,
+                bool edns0_do,
+                bool include_rfc6975,
+                int rcode,
+                size_t *start) {
+
         size_t saved_size;
         int r;
 
@@ -732,8 +739,10 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, in
                 goto fail;
 
         /* RDLENGTH */
-        if (edns0_do && !DNS_PACKET_QR(p)) {
-                /* If DO is on and this is not a reply, also append RFC6975 Algorithm data */
+        if (edns0_do && include_rfc6975) {
+                /* If DO is on and this is requested, also append RFC6975 Algorithm data. This is supposed to
+                 * be done on queries, not on replies, hencer callers should turn this off when finishing off
+                 * replies. */
 
                 static const uint8_t rfc6975[] = {
 
@@ -1426,7 +1435,7 @@ int dns_packet_read_name(
 
                         n += r;
                         continue;
-                } else if (allow_compression && (c & 0xc0) == 0xc0) {
+                } else if (allow_compression && FLAGS_SET(c, 0xc0)) {
                         uint16_t ptr;
 
                         /* Pointer */
@@ -2241,12 +2250,11 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
                         if (DNS_PACKET_QR(p)) {
                                 /* Additional checks for responses */
 
-                                if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr)) {
+                                if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr))
                                         /* If this is a reply and we don't know the EDNS version
                                          * then something is weird... */
-                                        log_debug("EDNS version newer that our request, bad server.");
-                                        return -EBADMSG;
-                                }
+                                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                                               "EDNS version newer that our request, bad server.");
 
                                 if (has_rfc6975) {
                                         /* If the OPT RR contains RFC6975 algorithm data, then this
index 56614c4a071756ad76ca59c7f20089fe5a27a166..964aff38c4629df38426f9a642ea3e8af6abdc7a 100644 (file)
@@ -198,7 +198,7 @@ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonica
 int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start);
 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start);
 int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start);
-int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start);
+int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, int rcode, size_t *start);
 int dns_packet_append_question(DnsPacket *p, DnsQuestion *q);
 int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a);
 
index 3afe4cf73bcce7ac12c9da716f77c365e7b7aeab..1eff893b21de6126bf824ac50f95b5772640fe88 100644 (file)
@@ -908,13 +908,11 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
         if (r == 0 && k == 0) /* No actual cname happened? */
                 return -ELOOP;
 
-        if (q->answer_protocol == DNS_PROTOCOL_DNS) {
+        if (q->answer_protocol == DNS_PROTOCOL_DNS)
                 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
                  * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
                  * ones. */
-
                 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
-        }
 
         /* Turn off searching for the new name */
         q->flags |= SD_RESOLVED_NO_SEARCH;
index a5b89128c7da40e9d22d2c34f6adf651852bdcbc..d9ac44f9b5b58f4687197df08560698d72d7f899 100644 (file)
@@ -535,7 +535,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
         else
                 packet_size = server->received_udp_packet_max;
 
-        return dns_packet_append_opt(packet, packet_size, edns_do, 0, NULL);
+        return dns_packet_append_opt(packet, packet_size, edns_do, /* include_rfc6975 = */ true, 0, NULL);
 }
 
 int dns_server_ifindex(const DnsServer *s) {
index 5c6da94b3362102efc7ff79c2552e8ce6d17277f..445fa86dd1fca6e060438f7ba6f4e82eccfedab3 100644 (file)
@@ -162,7 +162,7 @@ static int dns_stub_finish_reply_packet(
         assert(p);
 
         if (add_opt) {
-                r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
+                r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, /* include_rfc6975 = */ false, rcode, NULL);
                 if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */
                         tc = true;
                 else if (r < 0)
index 8ffe45e744fcb0dce53b46ae6ff935a7a39545ff..d7f3a5adef2ee6eed245b5e9604cb12f81169a19 100644 (file)
@@ -97,15 +97,15 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
         if (r < 0)
                 return r;
 
-        if (!service->name_template) {
-                log_error("%s doesn't define service instance name", service->name);
-                return -EINVAL;
-        }
-
-        if (!service->type) {
-                log_error("%s doesn't define service type", service->name);
-                return -EINVAL;
-        }
+        if (!service->name_template)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s doesn't define service instance name",
+                                       service->name);
+
+        if (!service->type)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s doesn't define service type",
+                                       service->name);
 
         if (LIST_IS_EMPTY(service->txt_data_items)) {
                 txt_data = new0(DnssdTxtData, 1);
index 7523c65e9641a3cc67a820698162d47e0aa11174..c19710881091dec3284e29eb7fc56e5b7137ef20 100644 (file)
@@ -8,10 +8,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#if HAVE_LIBIDN2
-#include <idn2.h>
-#endif
-
 #include "af-list.h"
 #include "alloc-util.h"
 #include "bus-polkit.h"
@@ -20,6 +16,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
+#include "idn-util.h"
 #include "io-util.h"
 #include "missing_network.h"
 #include "netlink-util.h"
@@ -346,29 +343,38 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Couldn't find a single label in hostname.");
 
+#if HAVE_LIBIDN || HAVE_LIBIDN2
+        r = dlopen_idn();
+        if (r < 0) {
+                log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m");
+                decoded = label; /* no decoding */
+        } else
+#endif
+        {
 #if HAVE_LIBIDN2
-        r = idn2_to_unicode_8z8z(label, &utf8, 0);
-        if (r != IDN2_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
-                                       "Failed to undo IDNA: %s", idn2_strerror(r));
-        assert(utf8_is_valid(utf8));
-
-        r = strlen(utf8);
-        decoded = utf8;
+                r = sym_idn2_to_unicode_8z8z(label, &utf8, 0);
+                if (r != IDN2_OK)
+                        return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
+                                               "Failed to undo IDNA: %s", sym_idn2_strerror(r));
+                assert(utf8_is_valid(utf8));
+
+                r = strlen(utf8);
+                decoded = utf8;
 #elif HAVE_LIBIDN
-        k = dns_label_undo_idna(label, r, label, sizeof label);
-        if (k < 0)
-                return log_error_errno(k, "Failed to undo IDNA: %m");
-        if (k > 0)
-                r = k;
-
-        if (!utf8_is_valid(label))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "System hostname is not UTF-8 clean.");
-        decoded = label;
+                k = dns_label_undo_idna(label, r, label, sizeof label);
+                if (k < 0)
+                        return log_error_errno(k, "Failed to undo IDNA: %m");
+                if (k > 0)
+                        r = k;
+
+                if (!utf8_is_valid(label))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "System hostname is not UTF-8 clean.");
+                decoded = label;
 #else
-        decoded = label; /* no decoding */
+                decoded = label; /* no decoding */
 #endif
+        }
 
         r = dns_label_escape_new(decoded, r, &n);
         if (r < 0)
@@ -780,10 +786,8 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         l = recvmsg_safe(fd, &mh, 0);
         if (IN_SET(l, -EAGAIN, -EINTR))
                 return 0;
-        if (l < 0)
+        if (l <= 0)
                 return l;
-        if (l == 0)
-                return 0;
 
         assert(!(mh.msg_flags & MSG_TRUNC));
 
index 0de504636770e44eadecee35fbbe242bc867b61f..ba8f18f82d9b625b4ab901773c3e9cfc3e55ca8e 100644 (file)
@@ -15,6 +15,7 @@
 #include "resolved-dns-server.h"
 #include "resolved-resolv-conf.h"
 #include "stat-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util-label.h"
@@ -271,7 +272,10 @@ static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSe
                         write_resolv_conf_server(s, f, &count);
         }
 
-        if (!ordered_set_isempty(domains))
+        if (ordered_set_isempty(domains))
+                fputs("search .\n", f); /* Make sure that if the local hostname is chosen as fqdn this does not
+                                         * imply a search domain */
+        else
                 write_resolv_conf_search(domains, f);
 
         return fflush_and_check(f);
@@ -297,7 +301,10 @@ static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet
               "nameserver 127.0.0.53\n"
               "options edns0 trust-ad\n", f);
 
-        if (!ordered_set_isempty(domains))
+        if (ordered_set_isempty(domains))
+                fputs("search .\n", f); /* Make sure that if the local hostname is chosen as fqdn this does not
+                                         * imply a search domain */
+        else
                 write_resolv_conf_search(domains, f);
 
         return fflush_and_check(f);
@@ -371,3 +378,49 @@ int manager_write_resolv_conf(Manager *m) {
 
         return r;
 }
+
+int resolv_conf_mode(void) {
+        static const char * const table[_RESOLV_CONF_MODE_MAX] = {
+                [RESOLV_CONF_UPLINK] = PRIVATE_UPLINK_RESOLV_CONF,
+                [RESOLV_CONF_STUB] = PRIVATE_STUB_RESOLV_CONF,
+                [RESOLV_CONF_STATIC] = PRIVATE_STATIC_RESOLV_CONF,
+        };
+
+        struct stat system_st;
+
+        if (stat("/etc/resolv.conf", &system_st) < 0) {
+                if (errno == ENOENT)
+                        return RESOLV_CONF_MISSING;
+
+                return -errno;
+        }
+
+        for (ResolvConfMode m = 0; m < _RESOLV_CONF_MODE_MAX; m++) {
+                struct stat our_st;
+
+                if (!table[m])
+                        continue;
+
+                if (stat(table[m], &our_st) < 0) {
+                        if (errno != ENOENT)
+                                log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", table[m]);
+
+                        continue;
+                }
+
+                if (system_st.st_dev == our_st.st_dev &&
+                    system_st.st_ino == our_st.st_ino)
+                        return m;
+        }
+
+        return RESOLV_CONF_FOREIGN;
+}
+
+static const char* const resolv_conf_mode_table[_RESOLV_CONF_MODE_MAX] = {
+        [RESOLV_CONF_UPLINK] = "uplink",
+        [RESOLV_CONF_STUB] = "stub",
+        [RESOLV_CONF_STATIC] = "static",
+        [RESOLV_CONF_MISSING] = "missing",
+        [RESOLV_CONF_FOREIGN] = "foreign",
+};
+DEFINE_STRING_TABLE_LOOKUP(resolv_conf_mode, ResolvConfMode);
index f69cf2a441bab5fc7543aa43e7a01425c6a98b59..584d25c0f7cf729cfe3d9ec40f31ab0a17e51c77 100644 (file)
@@ -6,3 +6,18 @@
 int manager_check_resolv_conf(const Manager *m);
 int manager_read_resolv_conf(Manager *m);
 int manager_write_resolv_conf(Manager *m);
+
+typedef enum ResolvConfMode {
+        RESOLV_CONF_UPLINK,
+        RESOLV_CONF_STUB,
+        RESOLV_CONF_STATIC,
+        RESOLV_CONF_FOREIGN,
+        RESOLV_CONF_MISSING,
+        _RESOLV_CONF_MODE_MAX,
+        _RESOLV_CONF_MODE_INVALID = -1,
+} ResolvConfMode;
+
+int resolv_conf_mode(void);
+
+const char* resolv_conf_mode_to_string(ResolvConfMode m) _const_;
+ResolvConfMode resolv_conf_mode_from_string(const char *s) _pure_;
index 2a65293c2a64720cf8216d385faa8feed8cb7841..2f11a780911d5882dade7361817b8de964b38660 100644 (file)
@@ -93,7 +93,11 @@ static void vl_on_disconnect(VarlinkServer *s, Varlink *link, void *userdata) {
         dns_query_complete(q, DNS_TRANSACTION_ABORTED);
 }
 
-static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) {
+static bool validate_and_mangle_flags(
+                const char *name,
+                uint64_t *flags,
+                uint64_t ok) {
+
         assert(flags);
 
         /* This checks that the specified client-provided flags parameter actually makes sense, and mangles
@@ -116,6 +120,12 @@ static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) {
         if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
                 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
 
+        /* If the SD_RESOLVED_NO_SEARCH flag is acceptable, and the query name is dot-suffixed, turn off
+         * search domains. Note that DNS name normalization drops the dot suffix, hence we propagate this
+         * into the flags field as early as we can. */
+        if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0)
+                *flags |= SD_RESOLVED_NO_SEARCH;
+
         return true;
 }
 
@@ -285,7 +295,7 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va
         if (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6))
                 return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
 
-        if (!validate_and_mangle_flags(&p.flags, SD_RESOLVED_NO_SEARCH))
+        if (!validate_and_mangle_flags(p.name, &p.flags, SD_RESOLVED_NO_SEARCH))
                 return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
 
         r = parse_as_address(link, &p);
@@ -460,7 +470,7 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var
         if (FAMILY_ADDRESS_SIZE(p.family) != p.address_size)
                 return varlink_error(link, "io.systemd.UserDatabase.BadAddressSize", NULL);
 
-        if (!validate_and_mangle_flags(&p.flags, 0))
+        if (!validate_and_mangle_flags(NULL, &p.flags, 0))
                 return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
 
         r = dns_question_new_reverse(&question, p.family, &p.address);
index 082ad7162610993c8098fcefa01d8c464ec00f07..93279b3dff1a860e9acfd07c50d23f4765c1255f 100644 (file)
 # See resolved.conf(5) for details
 
 [Resolve]
+# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
+# Cloudflare: 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
+# Google:     8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844
+# Quad9:      9.9.9.9 2620:fe::fe
 #DNS=
 #FallbackDNS=@DNS_SERVERS@
 #Domains=
@@ -21,5 +25,6 @@
 #LLMNR=@DEFAULT_LLMNR_MODE@
 #Cache=yes
 #DNSStubListener=yes
+#DNSStubListenerExtra=
 #ReadEtcHosts=yes
 #ResolveUnicastSingleLabel=no
index 214b2695695e6fe5cbb009e42636ea0853f2facd..41796243131afac004b4564a0b7b4577ac1aff38 100644 (file)
@@ -538,14 +538,13 @@ static int parse_argv(int argc, char *argv[]) {
                 arg_aggressive_gc = true;
         }
 
-        if (arg_stdio == ARG_STDIO_AUTO) {
+        if (arg_stdio == ARG_STDIO_AUTO)
                 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
                  * to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
                  * pipeline, but we are neatly interactive with tty-level isolation otherwise. */
                 arg_stdio = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
                         ARG_STDIO_PTY :
                         ARG_STDIO_DIRECT;
-        }
 
         if (argc > optind) {
                 char **l;
@@ -1336,7 +1335,7 @@ static int start_transient_service(
                         if (c.cpu_usage_nsec != NSEC_INFINITY) {
                                 char ts[FORMAT_TIMESPAN_MAX];
                                 log_info("CPU time consumed: %s",
-                                         format_timespan(ts, sizeof ts, (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC));
+                                         format_timespan(ts, sizeof ts, DIV_ROUND_UP(c.cpu_usage_nsec, NSEC_PER_USEC), USEC_PER_MSEC));
                         }
 
                         if (c.ip_ingress_bytes != UINT64_MAX) {
index 11bba2c7edfadd737d7be627fcc26432f10f4f9b..189fa25639258bc28ac6cdae762f4a307e5ef83d 100644 (file)
@@ -80,7 +80,7 @@ static int boot_entry_load(
                 return log_oom();
 
         if (!efi_loader_entry_name_valid(tmp.id))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry: %s", tmp.id);
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
 
         tmp.path = strdup(path);
         if (!tmp.path)
@@ -327,7 +327,7 @@ static int boot_entry_load_unified(
                 return log_oom();
 
         if (!efi_loader_entry_name_valid(tmp.id))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry: %s", tmp.id);
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
 
         tmp.path = strdup(path);
         if (!tmp.path)
@@ -842,19 +842,21 @@ static int verify_esp_blkid(
         else if (r != 0)
                 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
 
-        errno = 0;
         r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system type of \"%s\": %m", node);
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "No filesystem found on \"%s\": %m", node);
         if (!streq(v, "vfat"))
                 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
                                       SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
                                       "File system \"%s\" is not FAT.", node);
 
-        errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "File system \"%s\" is not located on a partitioned block device.", node);
         if (!streq(v, "gpt"))
                 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
                                       SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
index 8ad4694046607ac719afe31c5058d9805925a6b1..5a123bb8f32ad859065fb8eb9a679d9e0ca5b31d 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "bus-get-properties.h"
 #include "rlimit-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 
 int bus_property_get_bool(
@@ -54,6 +55,23 @@ int bus_property_get_id128(
                 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
 }
 
+int bus_property_get_percent(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        char pstr[DECIMAL_STR_MAX(int) + 2];
+        int p = *(int*) userdata;
+
+        xsprintf(pstr, "%d%%", p);
+
+        return sd_bus_message_append_basic(reply, 's', pstr);
+}
+
 #if __SIZEOF_SIZE_T__ != 8
 int bus_property_get_size(
                 sd_bus *bus,
index 81af74309d965699c237214c3df09254cb84a3c5..f3934a86a25f8f192e3487760ec9c0331a01bfc5 100644 (file)
@@ -8,6 +8,7 @@
 int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 int bus_property_set_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error);
 int bus_property_get_id128(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+int bus_property_get_percent(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 
 #define bus_property_get_usec ((sd_bus_property_get_t) NULL)
 #define bus_property_set_usec ((sd_bus_property_set_t) NULL)
index ab393c395204c904642b29c78d14c8a45ca2bd96..5cc8ce222d865f70b7228aaa4f6c8cab8aabe45c 100644 (file)
@@ -25,6 +25,23 @@ int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_err
         return 0;
 }
 
+int bus_map_strv_sort(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        _cleanup_strv_free_ char **l = NULL;
+        char ***p = userdata;
+        int r;
+
+        r = bus_message_read_strv_extend(m, &l);
+        if (r < 0)
+                return r;
+
+        r = strv_extend_strv(p, l, false);
+        if (r < 0)
+                return r;
+
+        strv_sort(*p);
+        return 0;
+}
+
 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
         char type;
         int r;
index 11b899227b2f0895a85fc97c8596332f821eb661..94242ecc3f787e54bd9ba5095ee455c093a93aab 100644 (file)
@@ -18,6 +18,7 @@ enum {
 };
 
 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
+int bus_map_strv_sort(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_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map,
index 3ae3c12f92149165644996692cc97630b933ef21..89e0c5bb95e2d173d0abb3614fbc87bc0d0d814b 100644 (file)
@@ -432,7 +432,11 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni
 static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
         int r;
 
-        if (STR_IN_SET(field, "DevicePolicy", "Slice"))
+        if (STR_IN_SET(field, "DevicePolicy",
+                              "Slice",
+                              "ManagedOOMSwap",
+                              "ManagedOOMMemoryPressure",
+                              "ManagedOOMMemoryPressureLimitPercent"))
                 return bus_append_string(m, field, eq);
 
         if (STR_IN_SET(field, "CPUAccounting",
@@ -2407,3 +2411,20 @@ int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
 
         return 0;
 }
+
+int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
+        int r;
+
+        /* First, order by machine */
+        r = strcasecmp_ptr(a->machine, b->machine);
+        if (r != 0)
+                return r;
+
+        /* Second, order by unit type */
+        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
+        if (r != 0)
+                return r;
+
+        /* Third, order by name */
+        return strcasecmp(a->id, b->id);
+}
index a0b496f62c8a2088a679d3d00a00c65b6a20e868..544767b0336eb99e1439ccc812963eb18e11ae8a 100644 (file)
@@ -28,3 +28,5 @@ int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char
 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes);
 
 int unit_load_state(sd_bus *bus, const char *name, char **load_state);
+
+int unit_info_compare(const UnitInfo *a, const UnitInfo *b);
index 9a306daa032ba6574ee3718389316c339672da6c..aa5dadba45573f780113b0705eabf027ac553d9f 100644 (file)
@@ -266,12 +266,10 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
                 if (user)
                         r = sd_bus_default_user(&bus);
                 else {
-                        if (sd_booted() <= 0) {
+                        if (sd_booted() <= 0)
                                 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
-                                log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
-
-                                return -EHOSTDOWN;
-                        }
+                                return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
+                                                       "System has not been booted with systemd as init system (PID 1). Can't operate.");
                         r = sd_bus_default_system(&bus);
                 }
                 break;
index 9b86f9526e0c1b0049e5680c44561b7de7043288..1a1389fd1e84e291a64550d32fecbaccb85e8645 100644 (file)
@@ -38,13 +38,19 @@ int bus_connect_user_systemd(sd_bus **_bus);
 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
 
-#define bus_log_connect_error(r) \
-        log_error_errno(r, "Failed to create bus connection: %m")
-
-#define bus_log_parse_error(r) \
+#define bus_log_address_error(r)                                        \
+        log_error_errno(r,                                              \
+                r == -ENOMEDIUM ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
+                                  "Failed to set bus address: %m")
+#define bus_log_connect_error(r)                                        \
+        log_error_errno(r,                                              \
+                r == -ENOMEDIUM ? "Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
+                                  "Failed to connect to bus: %m")
+
+#define bus_log_parse_error(r)                                  \
         log_error_errno(r, "Failed to parse bus message: %m")
 
-#define bus_log_create_error(r) \
+#define bus_log_create_error(r)                                 \
         log_error_errno(r, "Failed to create bus message: %m")
 
 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
index db6a103c42a74ed382359a1e32fba5795efcb63c..bcc51f973c9054d5a3019fab07b11e527486d296 100644 (file)
@@ -363,7 +363,7 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
 
         if (c->utc)
                 fputs(" UTC", f);
-        else if (c->timezone != NULL) {
+        else if (c->timezone) {
                 fputc(' ', f);
                 fputs(c->timezone, f);
         } else if (IN_SET(c->dst, 0, 1)) {
index 636c0e2a7fdbf9a1ecb0d86639dba669e533cd84..cb75d9a11bdf453bd06d5360837626040043fd03 100644 (file)
@@ -124,7 +124,7 @@ int path_chown_recursive(
         if (fd < 0)
                 return -errno;
 
-        if (!uid_is_valid(uid) && !gid_is_valid(gid) && (mask & 07777) == 07777)
+        if (!uid_is_valid(uid) && !gid_is_valid(gid) && FLAGS_SET(mask, 07777))
                 return 0; /* nothing to do */
 
         if (fstat(fd, &st) < 0)
@@ -160,7 +160,7 @@ int fd_chown_recursive(
         if (!S_ISDIR(st.st_mode))
                 return -ENOTDIR;
 
-        if (!uid_is_valid(uid) && !gid_is_valid(gid) && (mask & 07777) == 07777)
+        if (!uid_is_valid(uid) && !gid_is_valid(gid) && FLAGS_SET(mask, 07777))
                 return 0; /* nothing to do */
 
         /* Shortcut, as above */
index e4cd2d30d0a34748e5075989072deae94c36cc8a..5d8f66c6028c3b65a3e7bad338ebacfed4eed1f7 100644 (file)
@@ -218,7 +218,7 @@ static int clean_sysvipc_msg(uid_t delete_uid, gid_t delete_gid, bool rm) {
         return ret;
 }
 
-static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid, bool rm) {
+static int clean_posix_shm_internal(const char *dirname, DIR *dir, uid_t uid, gid_t gid, bool rm) {
         struct dirent *de;
         int ret = 0, r;
 
@@ -234,7 +234,8 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid, bool rm) {
                         if (errno == ENOENT)
                                 continue;
 
-                        ret = log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
+                        ret = log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s/%s: %m",
+                                                dirname, de->d_name);
                         continue;
                 }
 
@@ -244,9 +245,10 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid, bool rm) {
                         kid = xopendirat(dirfd(dir), de->d_name, O_NOFOLLOW|O_NOATIME);
                         if (!kid) {
                                 if (errno != ENOENT)
-                                        ret = log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
+                                        ret = log_warning_errno(errno, "Failed to enter shared memory directory %s/%s: %m",
+                                                                dirname, de->d_name);
                         } else {
-                                r = clean_posix_shm_internal(kid, uid, gid, rm);
+                                r = clean_posix_shm_internal(de->d_name, kid, uid, gid, rm);
                                 if (r < 0)
                                         ret = r;
                         }
@@ -262,7 +264,8 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid, bool rm) {
                                 if (errno == ENOENT)
                                         continue;
 
-                                ret = log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
+                                ret = log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s/%s: %m",
+                                                        dirname, de->d_name);
                         } else {
                                 log_debug("Removed POSIX shared memory directory %s", de->d_name);
                                 if (ret == 0)
@@ -307,7 +310,7 @@ static int clean_posix_shm(uid_t uid, gid_t gid, bool rm) {
                 return log_warning_errno(errno, "Failed to open /dev/shm: %m");
         }
 
-        return clean_posix_shm_internal(dir, uid, gid, rm);
+        return clean_posix_shm_internal("/dev/shm", dir, uid, gid, rm);
 }
 
 static int clean_posix_mq(uid_t uid, gid_t gid, bool rm) {
index 0f0dd8281ca6fcdea3098a5ac1c4e722715bd307..8669547c1325e136956163132319d9b074bcb304 100644 (file)
@@ -151,9 +151,9 @@ int clock_apply_epoch(void) {
 
         if (stat(EPOCH_FILE, &st) < 0) {
                 if (errno != ENOENT)
-                        log_warning_errno(errno, "Cannot stat %s: %m\n", EPOCH_FILE);
+                        log_warning_errno(errno, "Cannot stat " EPOCH_FILE ": %m");
 
-                epoch_usec = ((usec_t) TIME_EPOCH * USEC_PER_SEC);
+                epoch_usec = (usec_t) TIME_EPOCH * USEC_PER_SEC;
         } else
                 epoch_usec = timespec_load(&st.st_mtim);
 
index 1f6105622a512de64b907b74ef774ab386a5a048..af5d48f55be313adf19af3e43446f951b8f4db4c 100644 (file)
@@ -43,6 +43,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "tomoyo-util.h"
+#include "user-record.h"
 #include "user-util.h"
 #include "util.h"
 #include "virt.h"
index 02a27e3a88695bd12d367694cb817462e389d032..524f57ff80782ed84348d4b7a8f928b7568e91a4 100644 (file)
@@ -1243,3 +1243,5 @@ int config_parse_vlanprotocol(const char* unit,
 
         return 0;
 }
+
+DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
index 57787ea033b7644d0b5a5a086d7770c9df083467..2514dcbf483cdb6d10e6aabc5c0400eedcf8bb09 100644 (file)
@@ -147,6 +147,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
 CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
 CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol);
+CONFIG_PARSER_PROTOTYPE(config_parse_percent);
 
 typedef enum Disabled {
         DISABLED_CONFIGURATION,
index 5e9eca1d9e73907cd4a786bcd6db96ddc6f13d79..04b8245310044643e7609f20c83d50cc6cc2517c 100644 (file)
@@ -17,6 +17,6 @@ static inline const char *notify_start(const char *start, const char *stop) {
 
 /* This is intended to be used with _cleanup_ attribute. */
 static inline void notify_on_cleanup(const char **p) {
-        if (p)
+        if (*p)
                 (void) sd_notify(false, *p);
 }
index eaf44f156c67e5acb0256f30505b7d8a81870bbc..cbd335721993e5fdc0680834fe2b9f45ec7abd7a 100644 (file)
@@ -224,7 +224,7 @@ static int wait_for_partitions_to_appear(
                         if (r < 0)
                                 return r;
                         if (r == 0)
-                                return log_debug_errno(EPROTONOSUPPORT,
+                                return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
                                                        "Device is a loop device and partition scanning is off!");
 
                         return -EINVAL; /* original error */
@@ -2148,6 +2148,8 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                                         log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line);
                         } else if (r == 0)
                                 log_debug("/etc/machine-id file is empty.");
+                        else if (streq(line, "uninitialized"))
+                                log_debug("/etc/machine-id file is uninitialized (likely aborted first boot).");
                         else
                                 log_debug("/etc/machine-id has unexpected length %i.", r);
 
index b812665315f63dc0dc872dc03660a1508c969743..35d2eaa9f1519b8fa49bca4239d80f99e0f5d68d 100644 (file)
@@ -1,12 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#if HAVE_LIBIDN2
-#  include <idn2.h>
-#elif HAVE_LIBIDN
-#  include <idna.h>
-#  include <stringprep.h>
-#endif
-
 #include <endian.h>
 #include <netinet/in.h>
 #include <stdio.h>
@@ -17,6 +10,7 @@
 #include "hashmap.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
+#include "idn-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
 #include "parse-util.h"
@@ -41,8 +35,9 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f
                                 /* Trailing dash */
                                 return -EINVAL;
 
-                        if (*n == '.')
+                        if (n[0] == '.' && (n[1] != 0 || !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT)))
                                 n++;
+
                         break;
                 }
 
@@ -139,7 +134,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f
                 return -EINVAL;
 
         /* More than one trailing dot? */
-        if (*n == '.')
+        if (n[0] == '.' && !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT))
                 return -EINVAL;
 
         if (sz >= 1 && d)
@@ -311,12 +306,17 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
         const char *p;
         bool contains_8bit = false;
         char buffer[DNS_LABEL_MAX+1];
+        int r;
 
         assert(encoded);
         assert(decoded);
 
         /* Converts an U-label into an A-label */
 
+        r = dlopen_idn();
+        if (r < 0)
+                return r;
+
         if (encoded_size <= 0)
                 return -EINVAL;
 
@@ -331,11 +331,11 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
                 return 0;
         }
 
-        input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+        input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
         if (!input)
                 return -ENOMEM;
 
-        if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
+        if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
                 return -EINVAL;
 
         l = strlen(buffer);
@@ -361,28 +361,33 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
         _cleanup_free_ char *result = NULL;
         uint32_t *output = NULL;
         size_t w;
+        int r;
 
         /* To be invoked after unescaping. Converts an A-label into an U-label. */
 
         assert(encoded);
         assert(decoded);
 
+        r = dlopen_idn();
+        if (r < 0)
+                return r;
+
         if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
                 return -EINVAL;
 
         if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX))
                 return 0;
 
-        input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+        input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
         if (!input)
                 return -ENOMEM;
 
         output_size = input_size;
         output = newa(uint32_t, output_size);
 
-        idna_to_unicode_44i(input, input_size, output, &output_size, 0);
+        sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0);
 
-        result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
+        result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
         if (!result)
                 return -ENOMEM;
         if (w <= 0)
@@ -1265,26 +1270,38 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
 }
 
 int dns_name_apply_idna(const char *name, char **ret) {
+
         /* Return negative on error, 0 if not implemented, positive on success. */
 
-#if HAVE_LIBIDN2
+#if HAVE_LIBIDN2 || HAVE_LIBIDN2
         int r;
+
+        r = dlopen_idn();
+        if (r == EOPNOTSUPP) {
+                *ret = NULL;
+                return 0;
+        }
+        if (r < 0)
+                return r;
+#endif
+
+#if HAVE_LIBIDN2
         _cleanup_free_ char *t = NULL;
 
         assert(name);
         assert(ret);
 
-        r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
-                           IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+        r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+                               IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
         log_debug("idn2_lookup_u8: %s → %s", name, t);
         if (r == IDN2_OK) {
                 if (!startswith(name, "xn--")) {
                         _cleanup_free_ char *s = NULL;
 
-                        r = idn2_to_unicode_8z8z(t, &s, 0);
+                        r = sym_idn2_to_unicode_8z8z(t, &s, 0);
                         if (r != IDN2_OK) {
                                 log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
-                                          t, r, idn2_strerror(r));
+                                          t, r, sym_idn2_strerror(r));
                                 return 0;
                         }
 
@@ -1300,7 +1317,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
                 return 1; /* *ret has been written */
         }
 
-        log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
+        log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, sym_idn2_strerror(r));
         if (r == IDN2_2HYPHEN)
                 /* The name has two hyphens — forbidden by IDNA2008 in some cases */
                 return 0;
@@ -1357,6 +1374,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
 
         return 1;
 #else
+        *ret = NULL;
         return 0;
 #endif
 }
@@ -1372,3 +1390,19 @@ int dns_name_is_valid_or_address(const char *name) {
 
         return dns_name_is_valid(name);
 }
+
+int dns_name_dot_suffixed(const char *name) {
+        const char *p = name;
+        int r;
+
+        for (;;) {
+                if (streq(p, "."))
+                        return true;
+
+                r = dns_label_unescape(&p, NULL, DNS_LABEL_MAX, DNS_LABEL_LEAVE_TRAILING_DOT);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return false;
+        }
+}
index 6ed512c6b1656515c3a17b99fe994e6baedcf84e..60de7af22721d892cf7cfba5dc76788d9177ce28 100644 (file)
@@ -25,8 +25,9 @@
 #define DNS_N_LABELS_MAX 127
 
 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 */
+        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 */
+        DNS_LABEL_LEAVE_TRAILING_DOT = 1 << 2, /* Leave trailing dot in place */
 } DNSLabelFlags;
 
 int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
@@ -110,3 +111,5 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret);
 int dns_name_apply_idna(const char *name, char **ret);
 
 int dns_name_is_valid_or_address(const char *name);
+
+int dns_name_dot_suffixed(const char *name);
index 8d638705964a1ebce44ca9c1247f96b130faf180..e36b4090adbe39d0d4fa591a2f485fb6ef7fbcd4 100644 (file)
@@ -437,7 +437,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
         return 0;
 }
 
-int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, netdev_ring_param *ring) {
+int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring) {
         struct ethtool_ringparam ecmd = {
                 .cmd = ETHTOOL_GRINGPARAM
         };
@@ -566,7 +566,7 @@ static int set_features_bit(
         return found ? 0 : -ENODATA;
 }
 
-int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features) {
+int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features) {
         _cleanup_free_ struct ethtool_gstrings *strings = NULL;
         struct ethtool_sfeatures *sfeatures;
         struct ifreq ifr = {};
@@ -777,7 +777,7 @@ int ethtool_set_glinksettings(
                 int *fd,
                 const char *ifname,
                 int autonegotiation,
-                uint32_t advertise[static N_ADVERTISE],
+                const uint32_t advertise[static N_ADVERTISE],
                 uint64_t speed,
                 Duplex duplex,
                 NetDevPort port) {
@@ -836,7 +836,7 @@ int ethtool_set_glinksettings(
         return r;
 }
 
-int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
+int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *channels) {
         struct ethtool_channels ecmd = {
                 .cmd = ETHTOOL_GCHANNELS
         };
index 47302417089874025badb0723cd47baa4cdde676..9e3f1ed51ae106a1c77d5ac1826972e4f6091a12 100644 (file)
@@ -101,12 +101,12 @@ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
 int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct ether_addr *ret);
 int ethtool_set_speed(int *ethtool_fd, const char *ifname, unsigned speed, Duplex duplex);
 int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol);
-int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, netdev_ring_param *ring);
-int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features);
+int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring);
+int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features);
 int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
-                              int autonegotiation, uint32_t advertise[static N_ADVERTISE],
+                              int autonegotiation, const uint32_t advertise[static N_ADVERTISE],
                               uint64_t speed, Duplex duplex, NetDevPort port);
-int ethtool_set_channels(int *ethtool_fd, const char *ifname, netdev_channels *channels);
+int ethtool_set_channels(int *ethtool_fd, const char *ifname, const netdev_channels *channels);
 int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
 
 const char *duplex_to_string(Duplex d) _const_;
index 7e876295ff16d296908b9c85ade9d2e73039adcf..1063baba5269501273e7bdb18cd41bf6372c5137 100644 (file)
@@ -66,6 +66,7 @@ typedef struct TableData {
 
         size_t minimum_width;       /* minimum width for the column */
         size_t maximum_width;       /* maximum width for the column */
+        size_t formatted_for_width; /* the width we tried to format for */
         unsigned weight;            /* the horizontal weight for this column, in case the table is expanded/compressed */
         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 */
@@ -164,7 +165,6 @@ 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;
 
@@ -172,8 +172,7 @@ Table *table_new_internal(const char *first_header, ...) {
 
         va_start(ap, first_header);
         for (;;) {
-                h = va_arg(ap, const char*);
-                if (!h)
+                if (!va_arg(ap, const char*))
                         break;
 
                 n_columns++;
@@ -185,7 +184,7 @@ Table *table_new_internal(const char *first_header, ...) {
                 return NULL;
 
         va_start(ap, first_header);
-        for (h = first_header; h; h = va_arg(ap, const char*)) {
+        for (const char *h = first_header; h; h = va_arg(ap, const char*)) {
                 TableCell *cell;
 
                 r = table_add_cell(t, &cell, TABLE_STRING, h);
@@ -213,7 +212,7 @@ static TableData *table_data_free(TableData *d) {
         free(d->formatted);
         free(d->url);
 
-        if (d->type == TABLE_STRV)
+        if (IN_SET(d->type, TABLE_STRV, TABLE_STRV_WRAPPED))
                 strv_free(d->strv);
 
         return mfree(d);
@@ -223,12 +222,10 @@ DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(TableData, table_data, table_data_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(TableData*, table_data_unref);
 
 Table *table_unref(Table *t) {
-        size_t i;
-
         if (!t)
                 return NULL;
 
-        for (i = 0; i < t->n_cells; i++)
+        for (size_t i = 0; i < t->n_cells; i++)
                 table_data_unref(t->data[i]);
 
         free(t->data);
@@ -252,6 +249,7 @@ static size_t table_data_size(TableDataType type, const void *data) {
                 return strlen(data) + 1;
 
         case TABLE_STRV:
+        case TABLE_STRV_WRAPPED:
                 return sizeof(char **);
 
         case TABLE_BOOLEAN:
@@ -376,7 +374,7 @@ static TableData *table_data_new(
         d->align_percent = align_percent;
         d->ellipsize_percent = ellipsize_percent;
 
-        if (type == TABLE_STRV) {
+        if (IN_SET(type, TABLE_STRV, TABLE_STRV_WRAPPED)) {
                 d->strv = strv_copy(data);
                 if (!d->strv)
                         return NULL;
@@ -817,6 +815,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         break;
 
                 case TABLE_STRV:
+                case TABLE_STRV_WRAPPED:
                         data = va_arg(ap, char * const *);
                         break;
 
@@ -1047,11 +1046,9 @@ int table_set_empty_string(Table *t, const char *empty) {
 }
 
 int table_set_display_all(Table *t) {
-        size_t allocated;
-
         assert(t);
 
-        allocated = t->n_display_map;
+        size_t allocated = t->n_display_map;
 
         if (!GREEDY_REALLOC(t->display_map, allocated, MAX(t->n_columns, allocated)))
                 return -ENOMEM;
@@ -1124,7 +1121,6 @@ int table_set_sort(Table *t, size_t first_column, ...) {
 }
 
 int table_hide_column_from_display(Table *t, size_t column) {
-        size_t allocated, cur = 0;
         int r;
 
         assert(t);
@@ -1137,7 +1133,7 @@ int table_hide_column_from_display(Table *t, size_t column) {
                         return r;
         }
 
-        allocated = t->n_display_map;
+        size_t allocated = t->n_display_map, cur = 0;
 
         for (size_t i = 0; i < allocated; i++) {
                 if (t->display_map[i] == column)
@@ -1169,6 +1165,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
                         return path_compare(a->string, b->string);
 
                 case TABLE_STRV:
+                case TABLE_STRV_WRAPPED:
                         return strv_compare(a->strv, b->strv);
 
                 case TABLE_BOOLEAN:
@@ -1247,7 +1244,6 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
 }
 
 static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
-        size_t i;
         int r;
 
         assert(t);
@@ -1262,7 +1258,7 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
                 return 1;
 
         /* Order other lines by the sorting map */
-        for (i = 0; i < t->n_sort_map; i++) {
+        for (size_t i = 0; i < t->n_sort_map; i++) {
                 TableData *d, *dd;
 
                 d = t->data[*a + t->sort_map[i]];
@@ -1277,10 +1273,46 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
         return CMP(*a, *b);
 }
 
-static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercasing) {
+static char* format_strv_width(char **strv, size_t column_width) {
+        _cleanup_fclose_ FILE *f = NULL;
+        size_t sz = 0;
+        _cleanup_free_ char *buf = NULL;
+
+        f = open_memstream_unlocked(&buf, &sz);
+        if (!f)
+                return NULL;
+
+        size_t position = 0;
+        char **p;
+        STRV_FOREACH(p, strv) {
+                size_t our_len = utf8_console_width(*p); /* This returns -1 on invalid utf-8 (which shouldn't happen).
+                                                          * If that happens, we'll just print one item per line. */
+
+                if (position == 0) {
+                        fputs(*p, f);
+                        position = our_len;
+                } else if (size_add(size_add(position, 1), our_len) <= column_width) {
+                        fprintf(f, " %s", *p);
+                        position = size_add(size_add(position, 1), our_len);
+                } else {
+                        fprintf(f, "\n%s", *p);
+                        position = our_len;
+                }
+        }
+
+        if (fflush_and_check(f) < 0)
+                return NULL;
+
+        f = safe_fclose(f);
+        return TAKE_PTR(buf);
+}
+
+static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercasing, size_t column_width, bool *have_soft) {
         assert(d);
 
-        if (d->formatted)
+        if (d->formatted &&
+            /* Only TABLE_STRV_WRAPPED adjust based on column_width so far… */
+            (d->type != TABLE_STRV_WRAPPED || d->formatted_for_width == column_width))
                 return d->formatted;
 
         switch (d->type) {
@@ -1290,13 +1322,12 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
         case TABLE_STRING:
         case TABLE_PATH:
                 if (d->uppercase && !avoid_uppercasing) {
-                        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++)
+                        char *q = d->formatted;
+                        for (char *p = d->string; *p; p++, q++)
                                 *q = (char) toupper((unsigned char) *p);
                         *q = 0;
 
@@ -1305,17 +1336,28 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
 
                 return d->string;
 
-        case TABLE_STRV: {
-                char *p;
+        case TABLE_STRV:
+                if (strv_isempty(d->strv))
+                        return strempty(t->empty_string);
+
+                d->formatted = strv_join(d->strv, "\n");
+                if (!d->formatted)
+                        return NULL;
+                break;
 
+        case TABLE_STRV_WRAPPED: {
                 if (strv_isempty(d->strv))
                         return strempty(t->empty_string);
 
-                p = strv_join(d->strv, "\n");
-                if (!p)
+                char *buf = format_strv_width(d->strv, column_width);
+                if (!buf)
                         return NULL;
 
-                d->formatted = p;
+                free_and_replace(d->formatted, buf);
+                d->formatted_for_width = column_width;
+                if (have_soft)
+                        *have_soft = true;
+
                 break;
         }
 
@@ -1632,16 +1674,19 @@ static int console_width_height(
 static int table_data_requested_width_height(
                 Table *table,
                 TableData *d,
+                size_t available_width,
                 size_t *ret_width,
-                size_t *ret_height) {
+                size_t *ret_height,
+                bool *have_soft) {
 
         _cleanup_free_ char *truncated = NULL;
         bool truncation_applied = false;
         size_t width, height;
         const char *t;
         int r;
+        bool soft = false;
 
-        t = table_data_format(table, d, false);
+        t = table_data_format(table, d, false, available_width, &soft);
         if (!t)
                 return -ENOMEM;
 
@@ -1669,6 +1714,8 @@ static int table_data_requested_width_height(
                 *ret_width = width;
         if (ret_height)
                 *ret_height = height;
+        if (have_soft && soft)
+                *have_soft = true;
 
         return truncation_applied;
 }
@@ -1678,7 +1725,6 @@ static char *align_string_mem(const char *str, const char *url, size_t new_lengt
         _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 */
@@ -1723,10 +1769,10 @@ static char *align_string_mem(const char *str, const char *url, size_t new_lengt
         if (!ret)
                 return NULL;
 
-        for (i = 0; i < lspace; i++)
+        for (size_t i = 0; i < lspace; i++)
                 ret[i] = ' ';
         memcpy(ret + lspace, clickable ?: str, clickable_length);
-        for (i = lspace + clickable_length; i < space + clickable_length; i++)
+        for (size_t i = lspace + clickable_length; i < space + clickable_length; i++)
                 ret[i] = ' ';
 
         ret[space + clickable_length] = 0;
@@ -1740,7 +1786,7 @@ static bool table_data_isempty(TableData *d) {
                 return true;
 
         /* Let's also consider an empty strv as truly empty. */
-        if (d->type == TABLE_STRV)
+        if (IN_SET(d->type, TABLE_STRV, TABLE_STRV_WRAPPED))
                 return strv_isempty(d->strv);
 
         /* Note that an empty string we do not consider empty here! */
@@ -1771,8 +1817,8 @@ static const char* table_data_rgap_color(TableData *d) {
 
 int table_print(Table *t, FILE *f) {
         size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width,
-                i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
-                *width;
+                table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
+                *width = NULL;
         _cleanup_free_ size_t *sorted = NULL;
         uint64_t *column_weight, weight_sum;
         int r;
@@ -1795,7 +1841,7 @@ int table_print(Table *t, FILE *f) {
                 if (!sorted)
                         return -ENOMEM;
 
-                for (i = 0; i < n_rows; i++)
+                for (size_t i = 0; i < n_rows; i++)
                         sorted[i] = i * t->n_columns;
 
                 typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
@@ -1811,205 +1857,225 @@ int table_print(Table *t, FILE *f) {
         minimum_width = newa(size_t, display_columns);
         maximum_width = newa(size_t, display_columns);
         requested_width = newa(size_t, display_columns);
-        width = newa(size_t, display_columns);
         column_weight = newa0(uint64_t, display_columns);
 
-        for (j = 0; j < display_columns; j++) {
+        for (size_t j = 0; j < display_columns; j++) {
                 minimum_width[j] = 1;
                 maximum_width[j] = (size_t) -1;
-                requested_width[j] = (size_t) -1;
         }
 
-        /* First pass: determine column sizes */
-        for (i = t->header ? 0 : 1; i < n_rows; i++) {
-                TableData **row;
+        for (unsigned pass = 0; pass < 2; pass++) {
+                /* First pass: determine column sizes */
 
-                /* Note that we don't care about ordering at this time, as we just want to determine column sizes,
-                 * hence we don't care for sorted[] during the first pass. */
-                row = t->data + i * t->n_columns;
+                for (size_t j = 0; j < display_columns; j++)
+                        requested_width[j] = (size_t) -1;
 
-                for (j = 0; j < display_columns; j++) {
-                        TableData *d;
-                        size_t req_width, req_height;
+                bool any_soft = false;
 
-                        assert_se(d = row[t->display_map ? t->display_map[j] : j]);
+                for (size_t i = t->header ? 0 : 1; i < n_rows; i++) {
+                        TableData **row;
 
-                        r = table_data_requested_width_height(t, d, &req_width, &req_height);
-                        if (r < 0)
-                                return r;
-                        if (r > 0) { /* Truncated because too many lines? */
-                                _cleanup_free_ char *last = NULL;
-                                const char *field;
+                        /* Note that we don't care about ordering at this time, as we just want to determine column sizes,
+                         * hence we don't care for sorted[] during the first pass. */
+                        row = t->data + i * t->n_columns;
 
-                                /* If we are going to show only the first few lines of a cell that has
-                                 * multiple make sure that we have enough space horizontally to show an
-                                 * ellipsis. Hence, let's figure out the last line, and account for its
-                                 * length plus ellipsis. */
+                        for (size_t j = 0; j < display_columns; j++) {
+                                TableData *d;
+                                size_t req_width, req_height;
 
-                                field = table_data_format(t, d, false);
-                                if (!field)
-                                        return -ENOMEM;
+                                assert_se(d = row[t->display_map ? t->display_map[j] : j]);
 
-                                assert_se(t->cell_height_max > 0);
-                                r = string_extract_line(field, t->cell_height_max-1, &last);
+                                r = table_data_requested_width_height(t, d,
+                                                                      width ? width[j] : SIZE_MAX,
+                                                                      &req_width, &req_height, &any_soft);
                                 if (r < 0)
                                         return r;
+                                if (r > 0) { /* Truncated because too many lines? */
+                                        _cleanup_free_ char *last = NULL;
+                                        const char *field;
+
+                                        /* If we are going to show only the first few lines of a cell that has
+                                         * multiple make sure that we have enough space horizontally to show an
+                                         * ellipsis. Hence, let's figure out the last line, and account for its
+                                         * length plus ellipsis. */
+
+                                        field = table_data_format(t, d, false,
+                                                                  width ? width[j] : SIZE_MAX,
+                                                                  &any_soft);
+                                        if (!field)
+                                                return -ENOMEM;
 
-                                req_width = MAX(req_width,
-                                                utf8_console_width(last) +
-                                                utf8_console_width(special_glyph(SPECIAL_GLYPH_ELLIPSIS)));
-                        }
+                                        assert_se(t->cell_height_max > 0);
+                                        r = string_extract_line(field, t->cell_height_max-1, &last);
+                                        if (r < 0)
+                                                return r;
 
-                        /* Determine the biggest width that any cell in this column would like to have */
-                        if (requested_width[j] == (size_t) -1 ||
-                            requested_width[j] < req_width)
-                                requested_width[j] = req_width;
+                                        req_width = MAX(req_width,
+                                                        utf8_console_width(last) +
+                                                        utf8_console_width(special_glyph(SPECIAL_GLYPH_ELLIPSIS)));
+                                }
 
-                        /* Determine the minimum width any cell in this column needs */
-                        if (minimum_width[j] < d->minimum_width)
-                                minimum_width[j] = d->minimum_width;
+                                /* Determine the biggest width that any cell in this column would like to have */
+                                if (requested_width[j] == (size_t) -1 ||
+                                    requested_width[j] < req_width)
+                                        requested_width[j] = req_width;
 
-                        /* Determine the maximum width any cell in this column needs */
-                        if (d->maximum_width != (size_t) -1 &&
-                            (maximum_width[j] == (size_t) -1 ||
-                             maximum_width[j] > d->maximum_width))
-                                maximum_width[j] = d->maximum_width;
+                                /* Determine the minimum width any cell in this column needs */
+                                if (minimum_width[j] < d->minimum_width)
+                                        minimum_width[j] = d->minimum_width;
 
-                        /* Determine the full columns weight */
-                        column_weight[j] += d->weight;
+                                /* Determine the maximum width any cell in this column needs */
+                                if (d->maximum_width != (size_t) -1 &&
+                                    (maximum_width[j] == (size_t) -1 ||
+                                     maximum_width[j] > d->maximum_width))
+                                        maximum_width[j] = d->maximum_width;
+
+                                /* Determine the full columns weight */
+                                column_weight[j] += d->weight;
+                        }
                 }
-        }
 
-        /* One space between each column */
-        table_requested_width = table_minimum_width = table_maximum_width = display_columns - 1;
+                /* One space between each column */
+                table_requested_width = table_minimum_width = table_maximum_width = display_columns - 1;
 
-        /* Calculate the total weight for all columns, plus the minimum, maximum and requested width for the table. */
-        weight_sum = 0;
-        for (j = 0; j < display_columns; j++) {
-                weight_sum += column_weight[j];
+                /* Calculate the total weight for all columns, plus the minimum, maximum and requested width for the table. */
+                weight_sum = 0;
+                for (size_t j = 0; j < display_columns; j++) {
+                        weight_sum += column_weight[j];
 
-                table_minimum_width += minimum_width[j];
+                        table_minimum_width += minimum_width[j];
+
+                        if (maximum_width[j] == (size_t) -1)
+                                table_maximum_width = (size_t) -1;
+                        else
+                                table_maximum_width += maximum_width[j];
 
-                if (maximum_width[j] == (size_t) -1)
-                        table_maximum_width = (size_t) -1;
+                        table_requested_width += requested_width[j];
+                }
+
+                /* Calculate effective table width */
+                if (t->width != 0 && t->width != (size_t) -1)
+                        table_effective_width = t->width;
+                else if (t->width == 0 ||
+                         ((pass > 0 || !any_soft) && (pager_have() || !isatty(STDOUT_FILENO))))
+                        table_effective_width = table_requested_width;
                 else
-                        table_maximum_width += maximum_width[j];
+                        table_effective_width = MIN(table_requested_width, columns());
 
-                table_requested_width += requested_width[j];
-        }
+                if (table_maximum_width != (size_t) -1 && table_effective_width > table_maximum_width)
+                        table_effective_width = table_maximum_width;
 
-        /* Calculate effective table width */
-        if (t->width != 0 && t->width != (size_t) -1)
-                table_effective_width = t->width;
-        else if (t->width == 0 || pager_have() || !isatty(STDOUT_FILENO))
-                table_effective_width = table_requested_width;
-        else
-                table_effective_width = MIN(table_requested_width, columns());
+                if (table_effective_width < table_minimum_width)
+                        table_effective_width = table_minimum_width;
 
-        if (table_maximum_width != (size_t) -1 && table_effective_width > table_maximum_width)
-                table_effective_width = table_maximum_width;
+                if (!width)
+                        width = newa(size_t, display_columns);
 
-        if (table_effective_width < table_minimum_width)
-                table_effective_width = table_minimum_width;
+                if (table_effective_width >= table_requested_width) {
+                        size_t extra;
 
-        if (table_effective_width >= table_requested_width) {
-                size_t extra;
+                        /* We have extra room, let's distribute it among columns according to their weights. We first provide
+                         * each column with what it asked for and the distribute the rest.  */
 
-                /* We have extra room, let's distribute it among columns according to their weights. We first provide
-                 * each column with what it asked for and the distribute the rest.  */
+                        extra = table_effective_width - table_requested_width;
 
-                extra = table_effective_width - table_requested_width;
+                        for (size_t j = 0; j < display_columns; j++) {
+                                size_t delta;
 
-                for (j = 0; j < display_columns; j++) {
-                        size_t delta;
+                                if (weight_sum == 0)
+                                        width[j] = requested_width[j] + extra / (display_columns - j); /* Avoid division by zero */
+                                else
+                                        width[j] = requested_width[j] + (extra * column_weight[j]) / weight_sum;
 
-                        if (weight_sum == 0)
-                                width[j] = requested_width[j] + extra / (display_columns - j); /* Avoid division by zero */
-                        else
-                                width[j] = requested_width[j] + (extra * column_weight[j]) / weight_sum;
+                                if (maximum_width[j] != (size_t) -1 && width[j] > maximum_width[j])
+                                        width[j] = maximum_width[j];
 
-                        if (maximum_width[j] != (size_t) -1 && width[j] > maximum_width[j])
-                                width[j] = maximum_width[j];
+                                if (width[j] < minimum_width[j])
+                                        width[j] = minimum_width[j];
 
-                        if (width[j] < minimum_width[j])
-                                width[j] = minimum_width[j];
+                                assert(width[j] >= requested_width[j]);
+                                delta = width[j] - requested_width[j];
 
-                        assert(width[j] >= requested_width[j]);
-                        delta = width[j] - requested_width[j];
+                                /* Subtract what we just added from the rest */
+                                if (extra > delta)
+                                        extra -= delta;
+                                else
+                                        extra = 0;
 
-                        /* Subtract what we just added from the rest */
-                        if (extra > delta)
-                                extra -= delta;
-                        else
-                                extra = 0;
+                                assert(weight_sum >= column_weight[j]);
+                                weight_sum -= column_weight[j];
+                        }
 
-                        assert(weight_sum >= column_weight[j]);
-                        weight_sum -= column_weight[j];
-                }
+                        break; /* Every column should be happy, no need to repeat calculations. */
+                } else {
+                        /* We need to compress the table, columns can't get what they asked for. We first provide each column
+                         * with the minimum they need, and then distribute anything left. */
+                        bool finalize = false;
+                        size_t extra;
 
-        } else {
-                /* We need to compress the table, columns can't get what they asked for. We first provide each column
-                 * with the minimum they need, and then distribute anything left. */
-                bool finalize = false;
-                size_t extra;
+                        extra = table_effective_width - table_minimum_width;
 
-                extra = table_effective_width - table_minimum_width;
+                        for (size_t j = 0; j < display_columns; j++)
+                                width[j] = (size_t) -1;
 
-                for (j = 0; j < display_columns; j++)
-                        width[j] = (size_t) -1;
+                        for (;;) {
+                                bool restart = false;
 
-                for (;;) {
-                        bool restart = false;
+                                for (size_t j = 0; j < display_columns; j++) {
+                                        size_t delta, w;
 
-                        for (j = 0; j < display_columns; j++) {
-                                size_t delta, w;
+                                        /* Did this column already get something assigned? If so, let's skip to the next */
+                                        if (width[j] != (size_t) -1)
+                                                continue;
 
-                                /* Did this column already get something assigned? If so, let's skip to the next */
-                                if (width[j] != (size_t) -1)
-                                        continue;
+                                        if (weight_sum == 0)
+                                                w = minimum_width[j] + extra / (display_columns - j); /* avoid division by zero */
+                                        else
+                                                w = minimum_width[j] + (extra * column_weight[j]) / weight_sum;
 
-                                if (weight_sum == 0)
-                                        w = minimum_width[j] + extra / (display_columns - j); /* avoid division by zero */
-                                else
-                                        w = minimum_width[j] + (extra * column_weight[j]) / weight_sum;
+                                        if (w >= requested_width[j]) {
+                                                /* Never give more than requested. If we hit a column like this, there's more
+                                                 * space to allocate to other columns which means we need to restart the
+                                                 * iteration. However, if we hit a column like this, let's assign it the space
+                                                 * it wanted for good early.*/
 
-                                if (w >= requested_width[j]) {
-                                        /* Never give more than requested. If we hit a column like this, there's more
-                                         * space to allocate to other columns which means we need to restart the
-                                         * iteration. However, if we hit a column like this, let's assign it the space
-                                         * it wanted for good early.*/
+                                                w = requested_width[j];
+                                                restart = true;
 
-                                        w = requested_width[j];
-                                        restart = true;
+                                        } else if (!finalize)
+                                                continue;
 
-                                } else if (!finalize)
-                                        continue;
+                                        width[j] = w;
 
-                                width[j] = w;
+                                        assert(w >= minimum_width[j]);
+                                        delta = w - minimum_width[j];
 
-                                assert(w >= minimum_width[j]);
-                                delta = w - minimum_width[j];
+                                        assert(delta <= extra);
+                                        extra -= delta;
 
-                                assert(delta <= extra);
-                                extra -= delta;
+                                        assert(weight_sum >= column_weight[j]);
+                                        weight_sum -= column_weight[j];
 
-                                assert(weight_sum >= column_weight[j]);
-                                weight_sum -= column_weight[j];
+                                        if (restart && !finalize)
+                                                break;
+                                }
 
-                                if (restart && !finalize)
+                                if (finalize)
                                         break;
+
+                                if (!restart)
+                                        finalize = true;
                         }
 
-                        if (finalize)
+                        if (!any_soft) /* Some columns got less than requested. If some cells were "soft",
+                                        * let's try to reformat them with the new widths. Otherwise, let's
+                                        * move on. */
                                 break;
-
-                        if (!restart)
-                                finalize = true;
                 }
         }
 
         /* Second pass: show output */
-        for (i = t->header ? 0 : 1; i < n_rows; i++) {
+        for (size_t i = t->header ? 0 : 1; i < n_rows; i++) {
                 size_t n_subline = 0;
                 bool more_sublines;
                 TableData **row;
@@ -2023,7 +2089,7 @@ int table_print(Table *t, FILE *f) {
                         const char *gap_color = NULL;
                         more_sublines = false;
 
-                        for (j = 0; j < display_columns; j++) {
+                        for (size_t j = 0; j < display_columns; j++) {
                                 _cleanup_free_ char *buffer = NULL, *extracted = NULL;
                                 bool lines_truncated = false;
                                 const char *field, *color = NULL;
@@ -2032,7 +2098,7 @@ int table_print(Table *t, FILE *f) {
 
                                 assert_se(d = row[t->display_map ? t->display_map[j] : j]);
 
-                                field = table_data_format(t, d, false);
+                                field = table_data_format(t, d, false, width[j], NULL);
                                 if (!field)
                                         return -ENOMEM;
 
@@ -2247,6 +2313,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
                 return json_variant_new_string(ret, d->string);
 
         case TABLE_STRV:
+        case TABLE_STRV_WRAPPED:
                 return json_variant_new_array_strv(ret, d->strv);
 
         case TABLE_BOOLEAN:
@@ -2332,17 +2399,15 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
 }
 
 static char* string_to_json_field_name(const char *f) {
-        char *c, *x;
-
         /* Tries to make a string more suitable as JSON field name. There are no strict rules defined what a
          * field name can be hence this is a bit vague and black magic. Right now we only convert spaces to
          * underscores and leave everything as is. */
 
-        c = strdup(f);
+        char *c = strdup(f);
         if (!c)
                 return NULL;
 
-        for (x = c; *x; x++)
+        for (char *x = c; *x; x++)
                 if (isspace(*x))
                         *x = '_';
 
@@ -2352,7 +2417,7 @@ static char* string_to_json_field_name(const char *f) {
 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;
+        size_t n_rows, display_columns;
         int r;
 
         assert(t);
@@ -2372,7 +2437,7 @@ int table_to_json(Table *t, JsonVariant **ret) {
                         goto finish;
                 }
 
-                for (i = 0; i < n_rows; i++)
+                for (size_t i = 0; i < n_rows; i++)
                         sorted[i] = i * t->n_columns;
 
                 typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
@@ -2390,7 +2455,7 @@ int table_to_json(Table *t, JsonVariant **ret) {
                 goto finish;
         }
 
-        for (j = 0; j < display_columns; j++) {
+        for (size_t j = 0; j < display_columns; j++) {
                 _cleanup_free_ char *mangled = NULL;
                 const char *formatted;
                 TableData *d;
@@ -2398,7 +2463,7 @@ int table_to_json(Table *t, JsonVariant **ret) {
                 assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
 
                 /* Field names must be strings, hence format whatever we got here as a string first */
-                formatted = table_data_format(t, d, true);
+                formatted = table_data_format(t, d, true, SIZE_MAX, NULL);
                 if (!formatted) {
                         r = -ENOMEM;
                         goto finish;
@@ -2422,7 +2487,7 @@ int table_to_json(Table *t, JsonVariant **ret) {
                 goto finish;
         }
 
-        for (i = 1; i < n_rows; i++) {
+        for (size_t i = 1; i < n_rows; i++) {
                 TableData **row;
 
                 if (sorted)
@@ -2430,7 +2495,7 @@ int table_to_json(Table *t, JsonVariant **ret) {
                 else
                         row = t->data + i * t->n_columns;
 
-                for (j = 0; j < display_columns; j++) {
+                for (size_t j = 0; j < display_columns; j++) {
                         TableData *d;
                         size_t k;
 
index 1851f1d14a22a56e01427763c3926255ead3072c..0d7b7c48c5fba6feb604a3e2eb5bc2f6859f2915 100644 (file)
@@ -12,6 +12,7 @@ typedef enum TableDataType {
         TABLE_EMPTY,
         TABLE_STRING,
         TABLE_STRV,
+        TABLE_STRV_WRAPPED,
         TABLE_PATH,
         TABLE_BOOLEAN,
         TABLE_TIMESTAMP,
index d883eca5c785d692f06ced398a06b6a743ff9c44..ca88813602304e316e8d1c37fb1eb74ff094154b 100644 (file)
@@ -95,7 +95,19 @@ int fstab_filter_options(const char *opts, const char *names,
 
         if (!ret_filtered) {
                 for (const char *word = opts;;) {
-                        const char *end = word + strcspn(word, ",");
+                        const char *end = word;
+
+                        /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
+                         * the only valid escape sequence, so we can do a very simple test here. */
+                        for (;;) {
+                                size_t n = strcspn(end, ",");
+
+                                end += n;
+                                if (n > 0 && end[-1] == '\\')
+                                        end++;
+                                else
+                                        break;
+                        }
 
                         NULSTR_FOREACH(name, names) {
                                 if (end < word + strlen(name))
@@ -128,9 +140,10 @@ int fstab_filter_options(const char *opts, const char *names,
                                 break;
                 }
         } else {
-                stor = strv_split(opts, ",");
-                if (!stor)
-                        return -ENOMEM;
+                r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
+                if (r < 0)
+                        return r;
+
                 strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
                 if (!strv)
                         return -ENOMEM;
@@ -165,7 +178,7 @@ answer:
         if (ret_filtered) {
                 char *f;
 
-                f = strv_join(strv, ",");
+                f = strv_join_full(strv, ",", NULL, true);
                 if (!f)
                         return -ENOMEM;
 
index 04d2f86a4a3e32dc1843b285a33bb619244a3be7..d61b367d33709187338a3e54f377b40a6fb3393a 100644 (file)
@@ -4,6 +4,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "cgroup-util.h"
 #include "dropin.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -620,6 +621,11 @@ int generator_write_cryptsetup_service_section(
 }
 
 void log_setup_generator(void) {
-        log_set_prohibit_ipc(true);
-        log_setup_service();
+        /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
+        if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */)
+                log_set_prohibit_ipc(true);
+
+        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); /* This effectively means: journal for per-user generators, kmsg otherwise */
+        log_parse_environment();
+        (void) log_open();
 }
diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c
new file mode 100644 (file)
index 0000000..75d815d
--- /dev/null
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#if HAVE_LIBIDN2
+#  include <idn2.h>
+#elif HAVE_LIBIDN
+#  include <idna.h>
+#  include <stringprep.h>
+#endif
+
+#include "alloc-util.h"
+#include "dlfcn-util.h"
+#include "idn-util.h"
+
+#if HAVE_LIBIDN || HAVE_LIBIDN2
+static void* idn_dl = NULL;
+#endif
+
+#if HAVE_LIBIDN2
+int (*sym_idn2_lookup_u8)(const uint8_t* src, uint8_t** lookupname, int flags) = NULL;
+const char *(*sym_idn2_strerror)(int rc) = NULL;
+int (*sym_idn2_to_unicode_8z8z)(const char * input, char ** output, int flags) = NULL;
+
+int dlopen_idn(void) {
+        _cleanup_(dlclosep) void *dl = NULL;
+        int r;
+
+        if (idn_dl)
+                return 0; /* Already loaded */
+
+        dl = dlopen("libidn2.so.0", RTLD_LAZY);
+        if (!dl)
+                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "libidn2 support is not installed: %s", dlerror());
+
+        r = dlsym_many_and_warn(
+                        dl,
+                        LOG_DEBUG,
+                        &sym_idn2_lookup_u8, "idn2_lookup_u8",
+                        &sym_idn2_strerror, "idn2_strerror",
+                        &sym_idn2_to_unicode_8z8z, "idn2_to_unicode_8z8z",
+                        NULL);
+        if (r < 0)
+                return r;
+
+        /* Note that we never release the reference here, because there's no real reason to, after all this
+         * was traditionally a regular shared library dependency which lives forever too. */
+        idn_dl = TAKE_PTR(dl);
+
+        return 1;
+}
+#endif
+
+#if HAVE_LIBIDN
+int (*sym_idna_to_ascii_4i)(const uint32_t * in, size_t inlen, char *out, int flags);
+int (*sym_idna_to_unicode_44i)(const uint32_t * in, size_t inlen,uint32_t * out, size_t * outlen, int flags);
+char* (*sym_stringprep_ucs4_to_utf8)(const uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written);
+uint32_t* (*sym_stringprep_utf8_to_ucs4)(const char *str, ssize_t len, size_t *items_written);
+
+int dlopen_idn(void) {
+        _cleanup_(dlclosep) void *dl = NULL;
+        int r;
+
+        if (idn_dl)
+                return 0; /* Already loaded */
+
+        dl = dlopen("libidn.so.12", RTLD_LAZY);
+        if (!dl) {
+                /* libidn broke ABI in 1.34, but not in a way we care about (a new field got added to an
+                 * open-coded struct we do not use), hence support both versions. */
+                dl = dlopen("libidn.so.11", RTLD_LAZY);
+                if (!dl)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                               "libidn support is not installed: %s", dlerror());
+        }
+
+        r = dlsym_many_and_warn(
+                        dl,
+                        LOG_DEBUG,
+                        &sym_idna_to_ascii_4i, "idna_to_ascii_4i",
+                        &sym_idna_to_unicode_44i, "idna_to_unicode_44i",
+                        &sym_stringprep_ucs4_to_utf8, "stringprep_ucs4_to_utf8",
+                        &sym_stringprep_utf8_to_ucs4, "stringprep_utf8_to_ucs4",
+                        NULL);
+        if (r < 0)
+                return r;
+
+        idn_dl = TAKE_PTR(dl);
+
+        return 1;
+}
+#endif
diff --git a/src/shared/idn-util.h b/src/shared/idn-util.h
new file mode 100644 (file)
index 0000000..d958559
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if HAVE_LIBIDN2
+#  include <idn2.h>
+#elif HAVE_LIBIDN
+#  include <idna.h>
+#  include <stringprep.h>
+#endif
+
+#include <inttypes.h>
+
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
+int dlopen_idn(void);
+#else
+static inline int dlopen_idn(void) {
+        return -EOPNOTSUPP;
+}
+#endif
+
+#if HAVE_LIBIDN2
+extern int (*sym_idn2_lookup_u8)(const uint8_t* src, uint8_t** lookupname, int flags);
+extern const char *(*sym_idn2_strerror)(int rc);
+extern int (*sym_idn2_to_unicode_8z8z)(const char * input, char ** output, int flags);
+#endif
+
+#if HAVE_LIBIDN
+extern int (*sym_idna_to_ascii_4i)(const uint32_t * in, size_t inlen, char *out, int flags);
+extern int (*sym_idna_to_unicode_44i)(const uint32_t * in, size_t inlen,uint32_t * out, size_t * outlen, int flags);
+extern char* (*sym_stringprep_ucs4_to_utf8)(const uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written);
+extern uint32_t* (*sym_stringprep_utf8_to_ucs4)(const char *str, ssize_t len, size_t *items_written);
+#endif
index e938e59ab605ba0d99b8982b4934ff9a8fc56a8c..1d2cbc8aed980f4431b70bfac3388c99f07df1c0 100644 (file)
@@ -3892,7 +3892,7 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                 assert_se(value = json_variant_by_index(v, i+1));
 
                 for (p = table; p->name; p++)
-                        if (p->name == (const char*) -1 ||
+                        if (p->name == POINTER_MAX ||
                             streq_ptr(json_variant_string(key), p->name))
                                 break;
 
index 2f3d6756432f7a0ceb619666eae5019b98407db7..aaad0d9ff04df90d0a127b47c4a40dfc169b9461 100644 (file)
@@ -142,11 +142,40 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
         return (int) n_list;
 }
 
+static int add_local_gateway(
+                struct local_address **list,
+                size_t *n_list,
+                size_t *n_allocated,
+                int af,
+                int ifindex,
+                uint32_t metric,
+                const RouteVia *via) {
+
+        assert(list);
+        assert(n_list);
+        assert(n_allocated);
+        assert(via);
+
+        if (af != AF_UNSPEC && af != via->family)
+                return 0;
+
+        if (!GREEDY_REALLOC(*list, *n_allocated, *n_list + 1))
+                return -ENOMEM;
+
+        (*list)[(*n_list)++] = (struct local_address) {
+                .ifindex = ifindex,
+                .metric = metric,
+                .family = via->family,
+                .address = via->address,
+        };
+
+        return 0;
+}
+
 int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         _cleanup_free_ struct local_address *list = NULL;
-        sd_netlink_message *m = NULL;
         size_t n_list = 0, n_allocated = 0;
         int r;
 
@@ -172,12 +201,16 @@ int local_gateways(sd_netlink *context, int ifindex, int af, struct local_addres
         if (r < 0)
                 return r;
 
-        for (m = reply; m; m = sd_netlink_message_next(m)) {
-                struct local_address *a;
+        for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
+                _cleanup_ordered_set_free_free_ OrderedSet *multipath_routes = NULL;
+                _cleanup_free_ void *rta_multipath = NULL;
+                union in_addr_union gateway;
                 uint16_t type;
                 unsigned char dst_len, src_len, table;
-                uint32_t ifi;
+                uint32_t ifi, metric = 0;
+                size_t rta_len;
                 int family;
+                RouteVia via;
 
                 r = sd_netlink_message_get_errno(m);
                 if (r < 0)
@@ -208,48 +241,72 @@ int local_gateways(sd_netlink *context, int ifindex, int af, struct local_addres
                 if (table != RT_TABLE_MAIN)
                         continue;
 
-                r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
-                if (r == -ENODATA) /* Not all routes have an RTA_OIF attribute (for example nexthop ones) */
-                        continue;
-                if (r < 0)
+                r = sd_netlink_message_read_u32(m, RTA_PRIORITY, &metric);
+                if (r < 0 && r != -ENODATA)
                         return r;
-                if (ifindex > 0 && (int) ifi != ifindex)
-                        continue;
 
                 r = sd_rtnl_message_route_get_family(m, &family);
                 if (r < 0)
                         return r;
-                if (af != AF_UNSPEC && af != family)
+                if (!IN_SET(family, AF_INET, AF_INET6))
                         continue;
 
-                if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
-                        return -ENOMEM;
+                r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
+                if (r < 0 && r != -ENODATA)
+                        return r;
+                if (r >= 0) {
+                        if (ifi <= 0)
+                                return -EINVAL;
+                        if (ifindex > 0 && (int) ifi != ifindex)
+                                continue;
 
-                a = list + n_list;
+                        r = netlink_message_read_in_addr_union(m, RTA_GATEWAY, family, &gateway);
+                        if (r < 0 && r != -ENODATA)
+                                return r;
+                        if (r >= 0) {
+                                via.family = family;
+                                via.address = gateway;
+                                r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &via);
+                                if (r < 0)
+                                        return r;
 
-                switch (family) {
-                case AF_INET:
-                        r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
-                        if (r < 0)
                                 continue;
+                        }
 
-                        break;
-                case AF_INET6:
-                        r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
-                        if (r < 0)
+                        if (family != AF_INET)
                                 continue;
 
-                        break;
-                default:
-                        continue;
+                        r = sd_netlink_message_read(m, RTA_VIA, sizeof(via), &via);
+                        if (r < 0 && r != -ENODATA)
+                                return r;
+                        if (r >= 0) {
+                                r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &via);
+                                if (r < 0)
+                                        return r;
+
+                                continue;
+                        }
                 }
 
-                sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
+                r = sd_netlink_message_read_data(m, RTA_MULTIPATH, &rta_len, &rta_multipath);
+                if (r < 0 && r != -ENODATA)
+                        return r;
+                if (r >= 0) {
+                        MultipathRoute *mr;
 
-                a->ifindex = ifi;
-                a->family = family;
+                        r = rtattr_read_nexthop(rta_multipath, rta_len, family, &multipath_routes);
+                        if (r < 0)
+                                return r;
 
-                n_list++;
+                        ORDERED_SET_FOREACH(mr, multipath_routes) {
+                                if (ifindex > 0 && mr->ifindex != ifindex)
+                                        continue;
+
+                                r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &mr->gateway);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
         }
 
         typesafe_qsort(list, n_list, address_compare);
index 4f25c643d23e6c1eab946b52aa8cb96f13de71a8..f7d3e01b49384cbd57f507f5d8e580e90b333e65 100644 (file)
@@ -347,7 +347,7 @@ static int output_timestamp_monotonic(FILE *f, sd_journal *j, const char *monoto
 }
 
 static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) {
-        char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)];
+        char buf[MAX(FORMAT_TIMESTAMP_MAX, 64U)];
         struct tm *(*gettime_r)(const time_t *, struct tm *);
         struct tm tm;
         uint64_t x;
index 723e00e4377d06bd4eb00ad8188c7da007d61e07..0ed216f1aaa2358cd0008d1a3627771daef961c3 100644 (file)
@@ -117,6 +117,8 @@ shared_sources = files('''
         group-record.h
         id128-print.c
         id128-print.h
+        idn-util.c
+        idn-util.h
         ima-util.c
         ima-util.h
         import-util.c
@@ -187,6 +189,8 @@ shared_sources = files('''
         pkcs11-util.h
         pretty-print.c
         pretty-print.h
+        psi-util.c
+        psi-util.h
         ptyfwd.c
         ptyfwd.h
         pwquality-util.c
@@ -355,7 +359,6 @@ libshared_deps = [threads,
                   libcap,
                   libcrypt,
                   libgcrypt,
-                  libidn,
                   libiptc,
                   libkmod,
                   liblz4,
index 710b6376daf19527f946def2fd6021ae39cc4fef..0a701b0e92218ed313141e2d6e8ca9a1ae50333a 100644 (file)
@@ -12,6 +12,7 @@ static const NamingScheme naming_schemes[] = {
         { "v241", NAMING_V241 },
         { "v243", NAMING_V243 },
         { "v245", NAMING_V245 },
+        { "v247", NAMING_V247 },
         /* … add more schemes here, as the logic to name devices is updated … */
 };
 
index 6fb26d5cab4f276e0ba50f908827ed94485a87e2..db47d2909ea28a0b454315b23dcfd1eb57079322 100644 (file)
@@ -31,6 +31,7 @@ typedef enum NamingSchemeFlags {
         NAMING_NETDEVSIM           = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
         NAMING_LABEL_NOPREFIX      = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
         NAMING_NSPAWN_LONG_HASH    = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation  */
+        NAMING_BRIDGE_NO_SLOT      = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
 
         /* And now the masks that combine the features above */
         NAMING_V238 = 0,
@@ -39,6 +40,7 @@ typedef enum NamingSchemeFlags {
         NAMING_V241 = NAMING_V240 | NAMING_STABLE_VIRTUAL_MACS,
         NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
         NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH,
+        NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT,
 
         _NAMING_SCHEME_FLAGS_INVALID = -1,
 } NamingSchemeFlags;
index e03be6d23b2d7f24264412881b65f889fd607c3f..9af7009b3f3aa7823558496b64ebbe5be816eb11 100644 (file)
@@ -8,7 +8,10 @@
 #include <sys/prctl.h>
 #include <unistd.h>
 
+#include "sd-login.h"
+
 #include "copy.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "io-util.h"
@@ -152,8 +155,7 @@ int pager_open(PagerFlags flags) {
                         _exit(EXIT_FAILURE);
                 }
 
-                /* Initialize a good charset for less. This is
-                 * particularly important if we output UTF-8
+                /* Initialize a good charset for less. This is particularly important if we output UTF-8
                  * characters. */
                 less_charset = getenv("SYSTEMD_LESSCHARSET");
                 if (!less_charset && is_locale_utf8())
@@ -164,7 +166,43 @@ int pager_open(PagerFlags flags) {
                         _exit(EXIT_FAILURE);
                 }
 
-                if (pager_args) {
+                /* People might invoke us from sudo, don't needlessly allow less to be a way to shell out
+                 * privileged stuff. If the user set $SYSTEMD_PAGERSECURE, trust their configuration of the
+                 * pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE
+                 * wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we
+                 * know to be good. */
+                int use_secure_mode = getenv_bool_secure("SYSTEMD_PAGERSECURE");
+                bool trust_pager = use_secure_mode >= 0;
+                if (use_secure_mode == -ENXIO) {
+                        uid_t uid;
+
+                        r = sd_pid_get_owner_uid(0, &uid);
+                        if (r < 0)
+                                log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m");
+
+                        use_secure_mode = r < 0 || uid != geteuid();
+
+                } else if (use_secure_mode < 0) {
+                        log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m");
+                        use_secure_mode = true;
+                }
+
+                /* We generally always set variables used by less, even if we end up using a different pager.
+                 * They shouldn't hurt in any case, and ideally other pagers would look at them too. */
+                if (use_secure_mode)
+                        r = setenv("LESSSECURE", "1", 1);
+                else
+                        r = unsetenv("LESSSECURE");
+                if (r < 0) {
+                        log_error_errno(errno, "Failed to adjust environment variable LESSSECURE: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (trust_pager && pager_args) { /* The pager config might be set globally, and we cannot
+                                                  * know if the user adjusted it to be appropriate for the
+                                                  * secure mode. Thus, start the pager specified through
+                                                  * envvars only when $SYSTEMD_PAGERSECURE was explicitly set
+                                                  * as well. */
                         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");
@@ -176,13 +214,14 @@ int pager_open(PagerFlags flags) {
                                        "Failed to execute '%s', using fallback pagers: %m", pager_args[0]);
                 }
 
-                /* Debian's alternatives command for pagers is
-                 * called 'pager'. Note that we do not call
-                 * sensible-pagers here, since that is just a
-                 * shell script that implements a logic that
-                 * is similar to this one anyway, but is
-                 * Debian-specific. */
+                /* Debian's alternatives command for pagers is called 'pager'. Note that we do not call
+                 * sensible-pagers here, since that is just a shell script that implements a logic that is
+                 * similar to this one anyway, but is Debian-specific. */
                 FOREACH_STRING(exe, "pager", "less", "more") {
+                        /* Only less implements secure mode right now. */
+                        if (use_secure_mode && !streq(exe, "less"))
+                                continue;
+
                         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");
@@ -193,6 +232,7 @@ int pager_open(PagerFlags flags) {
                                        "Failed to execute '%s', using next fallback pager: %m", exe);
                 }
 
+                /* Our builtin is also very secure. */
                 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");
index 4088439f93ff918f3d33d5e52118dab4d37038c0..400cebb66fc953c51e7f037996d6d28ab5f9c05e 100644 (file)
@@ -791,8 +791,8 @@ static int slot_process(
 
         rv = m->C_GetTokenInfo(slotid, &token_info);
         if (rv == CKR_TOKEN_NOT_PRESENT) {
-                log_debug("Token not present in slot, ignoring.");
-                return -EAGAIN;
+                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                       "Token not present in slot, ignoring.");
         } else if (rv != CKR_OK) {
                 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid, p11_kit_strerror(rv));
                 return -EAGAIN;
@@ -808,10 +808,10 @@ static int slot_process(
                 return -EAGAIN;
         }
 
-        if (search_uri && !p11_kit_uri_match_token_info(search_uri, &token_info)) {
-                log_debug("Found non-matching token with URI %s.", token_uri_string);
-                return -EAGAIN;
-        }
+        if (search_uri && !p11_kit_uri_match_token_info(search_uri, &token_info))
+                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                       "Found non-matching token with URI %s.",
+                                       token_uri_string);
 
         log_debug("Found matching token with URI %s.", token_uri_string);
 
@@ -876,10 +876,9 @@ static int module_process(
                 log_warning("Failed to get slot list, ignoring module: %s", p11_kit_strerror(rv));
                 return -EAGAIN;
         }
-        if (n_slotids == 0) {
-                log_debug("This module has no slots? Ignoring module.");
-                return -EAGAIN;
-        }
+        if (n_slotids == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                       "This module has no slots? Ignoring module.");
 
         for (k = 0; k < n_slotids; k++) {
                 r = slot_process(
index edba23985f33f0faafccdc7b1b4b19ac05286246..f690f334a2afe6d0914abe1b7b7e4bb4107e3c9f 100644 (file)
@@ -174,7 +174,7 @@ int cat_files(const char *file, char **dropins, CatFlags flags) {
         if (file) {
                 r = cat_file(file, false);
                 if (r == -ENOENT && (flags & CAT_FLAGS_MAIN_FILE_OPTIONAL))
-                        printf("%s# config file %s not found%s\n",
+                        printf("%s# Configuration file %s not found%s\n",
                                ansi_highlight_magenta(),
                                file,
                                ansi_normal());
diff --git a/src/shared/psi-util.c b/src/shared/psi-util.c
new file mode 100644 (file)
index 0000000..21e965b
--- /dev/null
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "psi-util.h"
+#include "string-util.h"
+#include "stat-util.h"
+#include "strv.h"
+
+int read_resource_pressure(const char *path, PressureType type, ResourcePressure *ret) {
+        _cleanup_free_ char *line = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        unsigned field_filled = 0;
+        ResourcePressure rp = {};
+        const char *t, *cline;
+        char *word;
+        int r;
+
+        assert(path);
+        assert(IN_SET(type, PRESSURE_TYPE_SOME, PRESSURE_TYPE_FULL));
+        assert(ret);
+
+        if (type == PRESSURE_TYPE_SOME)
+                t = "some";
+        else if (type == PRESSURE_TYPE_FULL)
+                t = "full";
+        else
+                return -EINVAL;
+
+        r = fopen_unlocked(path, "re", &f);
+         if (r < 0)
+                 return r;
+
+        for (;;) {
+                _cleanup_free_ char *l = NULL;
+                char *w;
+
+                r = read_line(f, LONG_LINE_MAX, &l);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                w = first_word(l, t);
+                if (w) {
+                        line = TAKE_PTR(l);
+                        cline = w;
+                        break;
+                }
+        }
+
+        if (!line)
+                return -ENODATA;
+
+        /* extracts either avgX=Y.Z or total=X */
+        while ((r = extract_first_word(&cline, &word, NULL, 0)) > 0) {
+                _cleanup_free_ char *w = word;
+                const char *v;
+
+                if ((v = startswith(w, "avg10="))) {
+                        if (field_filled & (1U << 0))
+                                return -EINVAL;
+
+                        field_filled |= 1U << 0;
+                        r = parse_loadavg_fixed_point(v, &rp.avg10);
+                } else if ((v = startswith(w, "avg60="))) {
+                        if (field_filled & (1U << 1))
+                                return -EINVAL;
+
+                        field_filled |= 1U << 1;
+                        r = parse_loadavg_fixed_point(v, &rp.avg60);
+                } else if ((v = startswith(w, "avg300="))) {
+                        if (field_filled & (1U << 2))
+                                return -EINVAL;
+
+                        field_filled |= 1U << 2;
+                        r = parse_loadavg_fixed_point(v, &rp.avg300);
+                } else if ((v = startswith(w, "total="))) {
+                        if (field_filled & (1U << 3))
+                                return -EINVAL;
+
+                        field_filled |= 1U << 3;
+                        r = safe_atou64(v, &rp.total);
+                } else
+                        continue;
+
+                if (r < 0)
+                        return r;
+        }
+
+        if (r < 0)
+                return r;
+
+        if (field_filled != 15U)
+                return -EINVAL;
+
+        *ret = rp;
+        return 0;
+}
+
+int is_pressure_supported(void) {
+        const char *p;
+
+        FOREACH_STRING(p, "/proc/pressure/cpu", "/proc/pressure/io", "/proc/pressure/memory")
+                if (access(p, F_OK) < 0) {
+                        if (errno == ENOENT)
+                                return 0;
+                        return -errno;
+                }
+
+        return 1;
+}
diff --git a/src/shared/psi-util.h b/src/shared/psi-util.h
new file mode 100644 (file)
index 0000000..9810dbe
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "parse-util.h"
+#include "time-util.h"
+
+typedef enum PressureType {
+        PRESSURE_TYPE_SOME,
+        PRESSURE_TYPE_FULL,
+} PressureType;
+
+/* Averages are stored in fixed-point with 11 bit fractions */
+typedef struct ResourcePressure {
+        loadavg_t avg10;
+        loadavg_t avg60;
+        loadavg_t avg300;
+        usec_t total;
+} ResourcePressure;
+
+/** Upstream 4.20+ format
+ *
+ *  some avg10=0.22 avg60=0.17 avg300=1.11 total=58761459
+ *  full avg10=0.23 avg60=0.16 avg300=1.08 total=58464525
+ */
+int read_resource_pressure(const char *path, PressureType type, ResourcePressure *ret);
+
+/* Was the kernel compiled with CONFIG_PSI=y? 1 if yes, 0 if not, negative on error. */
+int is_pressure_supported(void);
index bb372d40010cf48aa334278b5cb9433f6a5d91a3..6bcdfff41a730c33f6b345d662135bf3b98d3ce7 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <signal.h>
 #include <stddef.h>
@@ -27,6 +28,8 @@
 struct PTYForward {
         sd_event *event;
 
+        int input_fd;
+        int output_fd;
         int master;
 
         PTYForwardFlags flags;
@@ -40,6 +43,9 @@ struct PTYForward {
         struct termios saved_stdin_attr;
         struct termios saved_stdout_attr;
 
+        bool close_input_fd:1;
+        bool close_output_fd:1;
+
         bool saved_stdin:1;
         bool saved_stdout:1;
 
@@ -73,25 +79,36 @@ struct PTYForward {
 
 static void pty_forward_disconnect(PTYForward *f) {
 
-        if (f) {
-                f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
-                f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
+        if (!f)
+                return;
 
-                f->master_event_source = sd_event_source_unref(f->master_event_source);
-                f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
-                f->event = sd_event_unref(f->event);
+        f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
+        f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
 
+        f->master_event_source = sd_event_source_unref(f->master_event_source);
+        f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
+        f->event = sd_event_unref(f->event);
+
+        if (f->output_fd >= 0) {
                 if (f->saved_stdout)
-                        tcsetattr(STDOUT_FILENO, TCSANOW, &f->saved_stdout_attr);
+                        (void) tcsetattr(f->output_fd, TCSANOW, &f->saved_stdout_attr);
+
+                /* STDIN/STDOUT should not be non-blocking normally, so let's reset it */
+                (void) fd_nonblock(f->output_fd, false);
+                if (f->close_output_fd)
+                        f->output_fd = safe_close(f->output_fd);
+        }
+
+        if (f->input_fd >= 0) {
                 if (f->saved_stdin)
-                        tcsetattr(STDIN_FILENO, TCSANOW, &f->saved_stdin_attr);
+                        (void) tcsetattr(f->input_fd, TCSANOW, &f->saved_stdin_attr);
 
-                f->saved_stdout = f->saved_stdin = false;
+                (void) fd_nonblock(f->input_fd, false);
+                if (f->close_input_fd)
+                        f->input_fd = safe_close(f->input_fd);
         }
 
-        /* STDIN/STDOUT should not be nonblocking normally, so let's unconditionally reset it */
-        (void) fd_nonblock(STDIN_FILENO, false);
-        (void) fd_nonblock(STDOUT_FILENO, false);
+        f->saved_stdout = f->saved_stdin = false;
 }
 
 static int pty_forward_done(PTYForward *f, int rcode) {
@@ -191,7 +208,7 @@ static int shovel(PTYForward *f) {
 
                 if (f->stdin_readable && f->in_buffer_full < LINE_MAX) {
 
-                        k = read(STDIN_FILENO, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full);
+                        k = read(f->input_fd, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full);
                         if (k < 0) {
 
                                 if (errno == EAGAIN)
@@ -275,7 +292,7 @@ static int shovel(PTYForward *f) {
 
                 if (f->stdout_writable && f->out_buffer_full > 0) {
 
-                        k = write(STDOUT_FILENO, f->out_buffer, f->out_buffer_full);
+                        k = write(f->output_fd, f->out_buffer, f->out_buffer_full);
                         if (k < 0) {
 
                                 if (errno == EAGAIN)
@@ -345,7 +362,7 @@ static int on_stdin_event(sd_event_source *e, int fd, uint32_t revents, void *us
         assert(e);
         assert(e == f->stdin_event_source);
         assert(fd >= 0);
-        assert(fd == STDIN_FILENO);
+        assert(fd == f->input_fd);
 
         if (revents & (EPOLLIN|EPOLLHUP))
                 f->stdin_readable = true;
@@ -360,7 +377,7 @@ static int on_stdout_event(sd_event_source *e, int fd, uint32_t revents, void *u
         assert(e);
         assert(e == f->stdout_event_source);
         assert(fd >= 0);
-        assert(fd == STDOUT_FILENO);
+        assert(fd == f->output_fd);
 
         if (revents & (EPOLLOUT|EPOLLHUP))
                 f->stdout_writable = true;
@@ -377,7 +394,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
         assert(e == f->sigwinch_event_source);
 
         /* The window size changed, let's forward that. */
-        if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
+        if (ioctl(f->output_fd, TIOCGWINSZ, &ws) >= 0)
                 (void) ioctl(f->master, TIOCSWINSZ, &ws);
 
         return 0;
@@ -400,6 +417,8 @@ int pty_forward_new(
         *f = (struct PTYForward) {
                 .flags = flags,
                 .master = -1,
+                .input_fd = -1,
+                .output_fd = -1,
         };
 
         if (event)
@@ -410,14 +429,42 @@ int pty_forward_new(
                         return r;
         }
 
-        if (!(flags & PTY_FORWARD_READ_ONLY)) {
-                r = fd_nonblock(STDIN_FILENO, true);
-                if (r < 0)
-                        return r;
-
-                r = fd_nonblock(STDOUT_FILENO, true);
-                if (r < 0)
-                        return r;
+        if (FLAGS_SET(flags, PTY_FORWARD_READ_ONLY))
+                f->output_fd = STDOUT_FILENO;
+        else {
+                /* If we shall be invoked in interactive mode, let's switch on non-blocking mode, so that we
+                 * never end up staving one direction while we block on the other. However, let's be careful
+                 * here and not turn on O_NONBLOCK for stdin/stdout directly, but of re-opened copies of
+                 * them. This has two advantages: when we are killed abruptly the stdin/stdout fds won't be
+                 * left in O_NONBLOCK state for the next process using them. In addition, if some process
+                 * running in the background wants to continue writing to our stdout it can do so without
+                 * being confused by O_NONBLOCK. */
+
+                f->input_fd = fd_reopen(STDIN_FILENO, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+                if (f->input_fd < 0) {
+                        /* Handle failures gracefully, after all certain fd types cannot be reopened
+                         * (sockets, …) */
+                        log_debug_errno(f->input_fd, "Failed to reopen stdin, using original fd: %m");
+
+                        r = fd_nonblock(STDIN_FILENO, true);
+                        if (r < 0)
+                                return r;
+
+                        f->input_fd = STDIN_FILENO;
+                } else
+                        f->close_input_fd = true;
+
+                f->output_fd = fd_reopen(STDOUT_FILENO, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+                if (f->output_fd < 0) {
+                        log_debug_errno(f->output_fd, "Failed to reopen stdout, using original fd: %m");
+
+                        r = fd_nonblock(STDOUT_FILENO, true);
+                        if (r < 0)
+                                return r;
+
+                        f->output_fd = STDOUT_FILENO;
+                } else
+                        f->close_output_fd = true;
         }
 
         r = fd_nonblock(master, true);
@@ -426,20 +473,20 @@ int pty_forward_new(
 
         f->master = master;
 
-        if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
+        if (ioctl(f->output_fd, TIOCGWINSZ, &ws) < 0)
                 /* If we can't get the resolution from the output fd, then use our internal, regular width/height,
                  * i.e. something derived from $COLUMNS and $LINES if set. */
-
                 ws = (struct winsize) {
                         .ws_row = lines(),
                         .ws_col = columns(),
                 };
-        }
 
         (void) ioctl(master, TIOCSWINSZ, &ws);
 
         if (!(flags & PTY_FORWARD_READ_ONLY)) {
-                if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
+                assert(f->input_fd >= 0);
+
+                if (tcgetattr(f->input_fd, &f->saved_stdin_attr) >= 0) {
                         struct termios raw_stdin_attr;
 
                         f->saved_stdin = true;
@@ -447,10 +494,10 @@ int pty_forward_new(
                         raw_stdin_attr = f->saved_stdin_attr;
                         cfmakeraw(&raw_stdin_attr);
                         raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
-                        tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
+                        tcsetattr(f->input_fd, TCSANOW, &raw_stdin_attr);
                 }
 
-                if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
+                if (tcgetattr(f->output_fd, &f->saved_stdout_attr) >= 0) {
                         struct termios raw_stdout_attr;
 
                         f->saved_stdout = true;
@@ -459,10 +506,10 @@ int pty_forward_new(
                         cfmakeraw(&raw_stdout_attr);
                         raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
                         raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
-                        tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
+                        tcsetattr(f->output_fd, TCSANOW, &raw_stdout_attr);
                 }
 
-                r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
+                r = sd_event_add_io(f->event, &f->stdin_event_source, f->input_fd, EPOLLIN|EPOLLET, on_stdin_event, f);
                 if (r < 0 && r != -EPERM)
                         return r;
 
@@ -470,7 +517,7 @@ int pty_forward_new(
                         (void) sd_event_source_set_description(f->stdin_event_source, "ptyfwd-stdin");
         }
 
-        r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f);
+        r = sd_event_add_io(f->event, &f->stdout_event_source, f->output_fd, EPOLLOUT|EPOLLET, on_stdout_event, f);
         if (r == -EPERM)
                 /* stdout without epoll support. Likely redirected to regular file. */
                 f->stdout_writable = true;
index 358960d5c4b279c481e81a9d7a273dcb06e374b3..4a541111f96fab5950a18ff254c2653964d5226f 100644 (file)
@@ -272,6 +272,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 .name = "@default",
                 .help = "System calls that are always permitted",
                 .value =
+                "cacheflush\0"
                 "clock_getres\0"
                 "clock_getres_time64\0"
                 "clock_gettime\0"
@@ -344,6 +345,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 .value =
                 "_llseek\0"
                 "close\0"
+                "close_range\0"
                 "dup\0"
                 "dup2\0"
                 "dup3\0"
@@ -690,7 +692,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
         },
         [SYSCALL_FILTER_SET_PROCESS] = {
                 .name = "@process",
-                .help = "Process control, execution, namespaceing operations",
+                .help = "Process control, execution, namespacing operations",
                 .value =
                 "arch_prctl\0"
                 "capget\0"      /* Able to query arbitrary processes */
@@ -1189,7 +1191,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
         }
 
         /* NOOP? */
-        if ((retain & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
+        if (FLAGS_SET(retain, NAMESPACE_FLAGS_ALL))
                 return 0;
 
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
@@ -1227,7 +1229,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                         unsigned long f;
 
                         f = namespace_flag_map[i].flag;
-                        if ((retain & f) == f) {
+                        if (FLAGS_SET(retain, f)) {
                                 log_debug("Permitting %s.", namespace_flag_map[i].name);
                                 continue;
                         }
index a5cb486c99e7d4207acf8762f1a9d0e33727f27b..808e2e6040b0a0539c469aa226b565d3b60e3791 100644 (file)
@@ -254,7 +254,7 @@ static int allocate_scope(void) {
         return 0;
 }
 
-int enter_cgroup_subroot(char **ret_cgroup) {
+static int enter_cgroup(char **ret_cgroup, bool enter_subroot) {
         _cleanup_free_ char *cgroup_root = NULL, *cgroup_subroot = NULL;
         CGroupMask supported;
         int r;
@@ -268,7 +268,13 @@ int enter_cgroup_subroot(char **ret_cgroup) {
                 return log_warning_errno(r, "cg_pid_get_path(NULL, 0, ...) failed: %m");
         assert(r >= 0);
 
-        assert_se(asprintf(&cgroup_subroot, "%s/%" PRIx64, cgroup_root, random_u64()) >= 0);
+        if (enter_subroot)
+                assert_se(asprintf(&cgroup_subroot, "%s/%" PRIx64, cgroup_root, random_u64()) >= 0);
+        else {
+                cgroup_subroot = strdup(cgroup_root);
+                assert_se(cgroup_subroot != NULL);
+        }
+
         assert_se(cg_mask_supported(&supported) >= 0);
 
         /* If this fails, then we don't mind as the later cgroup operations will fail too, and it's fine if
@@ -287,3 +293,51 @@ int enter_cgroup_subroot(char **ret_cgroup) {
 
         return 0;
 }
+
+int enter_cgroup_subroot(char **ret_cgroup) {
+        return enter_cgroup(ret_cgroup, true);
+}
+
+int enter_cgroup_root(char **ret_cgroup) {
+        return enter_cgroup(ret_cgroup, false);
+}
+
+const char *ci_environment(void) {
+        /* We return a string because we might want to provide multiple bits of information later on: not
+         * just the general CI environment type, but also whether we're sanitizing or not, etc. The caller is
+         * expected to use strstr on the returned value. */
+        static const char *ans = POINTER_MAX;
+        const char *p;
+        int r;
+
+        if (ans != POINTER_MAX)
+                return ans;
+
+        /* We allow specifying the environment with $CITYPE. Nobody uses this so far, but we are ready. */
+        p = getenv("CITYPE");
+        if (!isempty(p))
+                return (ans = p);
+
+        if (getenv_bool("TRAVIS") > 0)
+                return (ans = "travis");
+        if (getenv_bool("SEMAPHORE") > 0)
+                return (ans = "semaphore");
+        if (getenv_bool("GITHUB_ACTIONS") > 0)
+                return (ans = "github-actions");
+        if (getenv("AUTOPKGTEST_ARTIFACTS") || getenv("AUTOPKGTEST_TMP"))
+                return (ans = "autopkgtest");
+
+        FOREACH_STRING(p, "CI", "CONTINOUS_INTEGRATION") {
+                /* Those vars are booleans according to Semaphore and Travis docs:
+                 * https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
+                 * https://docs.semaphoreci.com/ci-cd-environment/environment-variables/#ci
+                 */
+                r = getenv_bool(p);
+                if (r > 0)
+                        return (ans = "unknown"); /* Some other unknown thing */
+                if (r == 0)
+                        return (ans = NULL);
+        }
+
+        return (ans = NULL);
+}
index 6817ef4860653c98403cdc04ec5a8ae79aea5087..552e0f2c22e8d85c4d1ea881c178a107eb3b4d27 100644 (file)
@@ -20,6 +20,7 @@ static inline bool manager_errno_skip_test(int r) {
 
 char* setup_fake_runtime_dir(void);
 int enter_cgroup_subroot(char **ret_cgroup);
+int enter_cgroup_root(char **ret_cgroup);
 int get_testdata_dir(const char *suffix, char **ret);
 const char* get_catalog_dir(void);
 bool slow_tests_enabled(void);
@@ -39,3 +40,6 @@ bool can_memlock(void);
         } else {                                                    \
                 printf("systemd not booted skipping '%s'\n", #x);   \
         }
+
+/* Provide a convenient way to check if we're running in CI. */
+const char *ci_environment(void);
index 8b27a6d0d0342e25510c7dec199fef934eb89329..98bbfb2ae3444ebc3b0cc61d930b50061f076b39 100644 (file)
@@ -118,12 +118,13 @@ static int device_new_from_dev_path(const char *devlink, sd_device **ret_device)
 
         assert(devlink);
 
-        r = stat(devlink, &st);
-        if (r < 0)
-                return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to stat() %s: %m", devlink);
+        if (stat(devlink, &st) < 0)
+                return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
+                                      "Failed to stat() %s: %m", devlink);
 
         if (!S_ISBLK(st.st_mode))
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "%s does not point to a block device: %m", devlink);
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK),
+                                       "%s does not point to a block device: %m", devlink);
 
         r = sd_device_new_from_devnum(ret_device, 'b', st.st_rdev);
         if (r < 0)
@@ -153,6 +154,22 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
         assert(data->sysname || data->devlink);
         assert(!data->device);
 
+        /* Ignore REMOVE events here. We are waiting for initialization after all, not de-initialization. We
+         * might see a REMOVE event from an earlier use of the device (devices by the same name are recycled
+         * by the kernel after all), which we should not get confused by. After all we cannot distinguish use
+         * cycles of the devices, as the udev queue is entirely asynchronous.
+         *
+         * If we see a REMOVE event here for the use cycle we actually care about then we won't notice of
+         * course, but that should be OK, given the timeout logic used on the wait loop: this will be noticed
+         * by means of -ETIMEDOUT. Thus we won't notice immediately, but eventually, and that should be
+         * sufficient for an error path that should regularly not happen.
+         *
+         * (And yes, we only need to special case REMOVE. It's the only "negative" event type, where a device
+         * ceases to exist. All other event types are "positive": the device exists and is registered in the
+         * udev database, thus whenever we see the event, we can consider it initialized.) */
+        if (device_for_action(device, DEVICE_ACTION_REMOVE))
+                return 0;
+
         if (data->sysname && sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname))
                 goto found;
 
@@ -174,10 +191,6 @@ found:
         return sd_event_exit(sd_device_monitor_get_event(monitor), 0);
 }
 
-static int device_timeout_handler(sd_event_source *s, uint64_t usec, void *userdata) {
-        return sd_event_exit(sd_event_source_get_event(s), -ETIMEDOUT);
-}
-
 static int device_wait_for_initialization_internal(
                 sd_device *_device,
                 const char *devlink,
@@ -247,7 +260,7 @@ static int device_wait_for_initialization_internal(
                 r = sd_event_add_time_relative(
                                 event, &timeout_source,
                                 CLOCK_MONOTONIC, timeout, 0,
-                                device_timeout_handler, NULL);
+                                NULL, INT_TO_PTR(-ETIMEDOUT));
                 if (r < 0)
                         return log_error_errno(r, "Failed to add timeout event source: %m");
         }
@@ -288,10 +301,12 @@ int device_is_renaming(sd_device *dev) {
         assert(dev);
 
         r = sd_device_get_property_value(dev, "ID_RENAMING", NULL);
-        if (r < 0 && r != -ENOENT)
+        if (r == -ENOENT)
+                return false;
+        if (r < 0)
                 return r;
 
-        return r >= 0;
+        return true;
 }
 
 bool device_for_action(sd_device *dev, DeviceAction action) {
index 7cb7d8a477e9a7533062285726066fa27723b456..201d27ab63a778a5c35ab1ffb810d92f6ba2c2f7 100644 (file)
@@ -18,13 +18,11 @@ static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
 }
 
 static void uid_range_coalesce(UidRange **p, unsigned *n) {
-        unsigned i, j;
-
         assert(p);
         assert(n);
 
-        for (i = 0; i < *n; i++) {
-                for (j = i + 1; j < *n; j++) {
+        for (unsigned i = 0; i < *n; i++) {
+                for (unsigned j = i + 1; j < *n; j++) {
                         UidRange *x = (*p)+i, *y = (*p)+j;
 
                         if (uid_range_intersect(x, y->start, y->nr)) {
@@ -59,7 +57,6 @@ static int uid_range_compare(const UidRange *a, const UidRange *b) {
 int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
         bool found = false;
         UidRange *x;
-        unsigned i;
 
         assert(p);
         assert(n);
@@ -67,7 +64,7 @@ int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
         if (nr <= 0)
                 return 0;
 
-        for (i = 0; i < *n; i++) {
+        for (unsigned i = 0; i < *n; i++) {
                 x = (*p) + i;
                 if (uid_range_intersect(x, start, nr)) {
                         found = true;
@@ -143,14 +140,13 @@ int uid_range_add_str(UidRange **p, unsigned *n, const char *s) {
 
 int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
         uid_t closest = UID_INVALID, candidate;
-        unsigned i;
 
         assert(p);
         assert(uid);
 
         candidate = *uid - 1;
 
-        for (i = 0; i < n; i++) {
+        for (unsigned i = 0; i < n; i++) {
                 uid_t begin, end;
 
                 begin = p[i].start;
@@ -173,12 +169,10 @@ int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
 }
 
 bool uid_range_contains(const UidRange *p, unsigned n, uid_t uid) {
-        unsigned i;
-
         assert(p);
         assert(uid);
 
-        for (i = 0; i < n; i++)
+        for (unsigned i = 0; i < n; i++)
                 if (uid >= p[i].start && uid < p[i].start + p[i].nr)
                         return true;
 
index 4149205b8abd9736f49929bd5fe2288b3d37e009..7e7b28eb55023b1cb12e6ebe89577eb9232ba11e 100644 (file)
@@ -5,6 +5,8 @@
 #include "cgroup-util.h"
 #include "dns-domain.h"
 #include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "fs-util.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #define DEFAULT_RATELIMIT_BURST 30
 #define DEFAULT_RATELIMIT_INTERVAL_USEC (1*USEC_PER_MINUTE)
 
+#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
+static int parse_alloc_uid(const char *path, const char *name, const char *t, uid_t *ret_uid) {
+        uid_t uid;
+        int r;
+
+        r = parse_uid(t, &uid);
+        if (r < 0)
+                return log_debug_errno(r, "%s: failed to parse %s %s, ignoring: %m", path, name, t);
+        if (uid == 0)
+                uid = 1;
+
+        *ret_uid = uid;
+        return 0;
+}
+#endif
+
+int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root) {
+        UGIDAllocationRange defs = {
+                .system_alloc_uid_min = SYSTEM_ALLOC_UID_MIN,
+                .system_uid_max = SYSTEM_UID_MAX,
+                .system_alloc_gid_min = SYSTEM_ALLOC_GID_MIN,
+                .system_gid_max = SYSTEM_GID_MAX,
+        };
+
+#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        if (!path)
+                path = "/etc/login.defs";
+
+        r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &f, NULL);
+        if (r == -ENOENT)
+                goto assign;
+        if (r < 0)
+                return log_debug_errno(r, "Failed to open %s: %m", path);
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                char *t;
+
+                r = read_line(f, LINE_MAX, &line);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to read %s: %m", path);
+                if (r == 0)
+                        break;
+
+                if ((t = first_word(line, "SYS_UID_MIN")))
+                        (void) parse_alloc_uid(path, "SYS_UID_MIN", t, &defs.system_alloc_uid_min);
+                else if ((t = first_word(line, "SYS_UID_MAX")))
+                        (void) parse_alloc_uid(path, "SYS_UID_MAX", t, &defs.system_uid_max);
+                else if ((t = first_word(line, "SYS_GID_MIN")))
+                        (void) parse_alloc_uid(path, "SYS_GID_MIN", t, &defs.system_alloc_gid_min);
+                else if ((t = first_word(line, "SYS_GID_MAX")))
+                        (void) parse_alloc_uid(path, "SYS_GID_MAX", t, &defs.system_gid_max);
+        }
+
+ assign:
+        if (defs.system_alloc_uid_min > defs.system_uid_max) {
+                log_debug("%s: SYS_UID_MIN > SYS_UID_MAX, resetting.", path);
+                defs.system_alloc_uid_min = MIN(defs.system_uid_max - 1, (uid_t) SYSTEM_ALLOC_UID_MIN);
+                /* Look at sys_uid_max to make sure sys_uid_min..sys_uid_max remains a valid range. */
+        }
+        if (defs.system_alloc_gid_min > defs.system_gid_max) {
+                log_debug("%s: SYS_GID_MIN > SYS_GID_MAX, resetting.", path);
+                defs.system_alloc_gid_min = MIN(defs.system_gid_max - 1, (gid_t) SYSTEM_ALLOC_GID_MIN);
+                /* Look at sys_gid_max to make sure sys_gid_min..sys_gid_max remains a valid range. */
+        }
+#endif
+
+        *ret_defs = defs;
+        return 0;
+}
+
+const UGIDAllocationRange *acquire_ugid_allocation_range(void) {
+#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
+        static thread_local UGIDAllocationRange defs = {
+#else
+        static const UGIDAllocationRange defs = {
+#endif
+                .system_alloc_uid_min = SYSTEM_ALLOC_UID_MIN,
+                .system_uid_max = SYSTEM_UID_MAX,
+                .system_alloc_gid_min = SYSTEM_ALLOC_GID_MIN,
+                .system_gid_max = SYSTEM_GID_MAX,
+        };
+
+#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
+        /* This function will ignore failure to read the file, so it should only be called from places where
+         * we don't crucially depend on the answer. In other words, it's appropriate for journald, but
+         * probably not for sysusers. */
+
+        static thread_local bool initialized = false;
+
+        if (!initialized) {
+                (void) read_login_defs(&defs, NULL, NULL);
+                initialized = true;
+        }
+#endif
+
+        return &defs;
+}
+
+bool uid_is_system(uid_t uid) {
+        const UGIDAllocationRange *defs;
+        assert_se(defs = acquire_ugid_allocation_range());
+
+        return uid <= defs->system_uid_max;
+}
+
+bool gid_is_system(gid_t gid) {
+        const UGIDAllocationRange *defs;
+        assert_se(defs = acquire_ugid_allocation_range());
+
+        return gid <= defs->system_gid_max;
+}
+
 UserRecord* user_record_new(void) {
         UserRecord *h;
 
index 357c246ea5f08622e4f45eb7f848950e0d733e5e..2e74b910c2756a54811471d87d8f4560acb49ff5 100644 (file)
 /* The default disk size to use when nothing else is specified, relative to free disk space */
 #define USER_DISK_SIZE_DEFAULT_PERCENT 85
 
+bool uid_is_system(uid_t uid);
+bool gid_is_system(gid_t gid);
+
+static inline bool uid_is_dynamic(uid_t uid) {
+        return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
+}
+
+static inline bool gid_is_dynamic(gid_t gid) {
+        return uid_is_dynamic((uid_t) gid);
+}
+
+static inline bool uid_is_container(uid_t uid) {
+        return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
+}
+
+static inline bool gid_is_container(gid_t gid) {
+        return uid_is_container((uid_t) gid);
+}
+
+typedef struct UGIDAllocationRange {
+        uid_t system_alloc_uid_min;
+        uid_t system_uid_max;
+        gid_t system_alloc_gid_min;
+        gid_t system_gid_max;
+} UGIDAllocationRange;
+
+int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root);
+const UGIDAllocationRange *acquire_ugid_allocation_range(void);
+
 typedef enum UserDisposition {
         USER_INTRINSIC,   /* root and nobody */
         USER_SYSTEM,      /* statically allocated users for system services */
index 86b5f08ae76dcd7f2f3e4a9d38c76ace2bbc706d..fabfe78280b5e44212aecf6a7311e7578d1b0e04 100644 (file)
@@ -418,6 +418,11 @@ static int varlink_test_disconnect(Varlink *v) {
         if (IN_SET(v->state, VARLINK_IDLE_CLIENT) && (v->write_disconnected || v->got_pollhup))
                 goto disconnect;
 
+        /* The server is still expecting to write more, but its write end is disconnected and it got a POLLHUP
+         * (i.e. from a disconnected client), so disconnect. */
+        if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE) && v->write_disconnected && v->got_pollhup)
+                goto disconnect;
+
         return 0;
 
 disconnect:
index 06a34b480d46307a07475599f9b7e86f48094f9c..030db39b2f5329e9b7bdfc2d3b2f34f367c63856 100644 (file)
@@ -171,3 +171,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServer *, varlink_server_unref);
 #define VARLINK_ERROR_METHOD_NOT_FOUND "org.varlink.service.MethodNotFound"
 #define VARLINK_ERROR_METHOD_NOT_IMPLEMENTED "org.varlink.service.MethodNotImplemented"
 #define VARLINK_ERROR_INVALID_PARAMETER "org.varlink.service.InvalidParameter"
+#define VARLINK_ERROR_SUBSCRIPTION_TAKEN "org.varlink.service.SubscriptionTaken"
index 60420140696b4cba87be588336e06427eb5c0d61..64dd623c809daecc2aba27b2a6542e53bb91664d 100644 (file)
@@ -522,17 +522,14 @@ static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdat
 
                 r = add_connection_socket(context, nfd);
                 if (r < 0) {
-                        log_error_errno(r, "Failed to accept connection, ignoring: %m");
-                        safe_close(fd);
+                        log_warning_errno(r, "Failed to accept connection, ignoring: %m");
+                        safe_close(nfd);
                 }
         }
 
         r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
-        if (r < 0) {
-                log_error_errno(r, "Error while re-enabling listener with ONESHOT: %m");
-                sd_event_exit(context->event, r);
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Error while re-enabling listener with ONESHOT: %m");
 
         return 1;
 }
@@ -561,11 +558,14 @@ static int add_listen_socket(Context *context, int fd) {
 
         r = set_ensure_put(&context->listen, NULL, source);
         if (r < 0) {
-                log_error_errno(r, "Failed to add source to set: %m");
                 sd_event_source_unref(source);
-                return r;
+                return log_error_errno(r, "Failed to add source to set: %m");
         }
 
+        r = sd_event_source_set_exit_on_failure(source, true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to enable exit-on-failure logic: %m");
+
         /* Set the watcher to oneshot in case other processes are also
          * watching to accept(). */
         r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
diff --git a/src/systemctl/systemctl-add-dependency.c b/src/systemctl/systemctl-add-dependency.c
new file mode 100644 (file)
index 0000000..049719a
--- /dev/null
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-add-dependency.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int add_dependency(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **names = NULL;
+        _cleanup_free_ char *target = NULL;
+        const char *verb = argv[0];
+        UnitFileChange *changes = NULL;
+        size_t n_changes = 0;
+        UnitDependency dep;
+        int r;
+
+        if (!argv[1])
+                return 0;
+
+        r = unit_name_mangle_with_suffix(argv[1], "as target",
+                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                         ".target", &target);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
+
+        r = mangle_names("as dependency", strv_skip(argv, 2), &names);
+        if (r < 0)
+                return r;
+
+        if (streq(verb, "add-wants"))
+                dep = UNIT_WANTS;
+        else if (streq(verb, "add-requires"))
+                dep = UNIT_REQUIRES;
+        else
+                assert_not_reached("Unknown verb");
+
+        if (install_client_side()) {
+                r = unit_file_add_dependency(arg_scope, unit_file_flags_from_args(), arg_root, names, target, dep, &changes, &n_changes);
+                unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
+
+                if (r > 0)
+                        r = 0;
+        } else {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus *bus;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                polkit_agent_open_maybe();
+
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "AddDependencyUnitFiles");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, names);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
+
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
+                if (r < 0)
+                        goto finish;
+
+                if (arg_no_reload) {
+                        r = 0;
+                        goto finish;
+                }
+
+                r = daemon_reload(argc, argv, userdata);
+        }
+
+finish:
+        unit_file_changes_free(changes, n_changes);
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-add-dependency.h b/src/systemctl/systemctl-add-dependency.h
new file mode 100644 (file)
index 0000000..14572d5
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int add_dependency(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-cancel-job.c b/src/systemctl/systemctl-cancel-job.c
new file mode 100644 (file)
index 0000000..ff211f3
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "parse-util.h"
+#include "systemctl-cancel-job.h"
+#include "systemctl-trivial-method.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int cancel_job(int argc, char *argv[], void *userdata) {
+        sd_bus *bus;
+        char **name;
+        int r;
+
+        if (argc <= 1) /* Shortcut to trivial_method() if no argument is given */
+                return trivial_method(argc, argv, userdata);
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        STRV_FOREACH(name, strv_skip(argv, 1)) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                uint32_t id;
+                int q;
+
+                q = safe_atou32(*name, &id);
+                if (q < 0)
+                        return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
+
+                q = bus_call_method(bus, bus_systemd_mgr, "CancelJob", &error, NULL, "u", id);
+                if (q < 0) {
+                        log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
+                        if (r == 0)
+                                r = q;
+                }
+        }
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-cancel-job.h b/src/systemctl/systemctl-cancel-job.h
new file mode 100644 (file)
index 0000000..f337bea
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int cancel_job(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-clean-or-freeze.c b/src/systemctl/systemctl-clean-or-freeze.c
new file mode 100644 (file)
index 0000000..ca15f75
--- /dev/null
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-wait-for-units.h"
+#include "systemctl-clean-or-freeze.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int clean_or_freeze_unit(int argc, char *argv[], void *userdata) {
+        _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
+        _cleanup_strv_free_ char **names = NULL;
+        int r, ret = EXIT_SUCCESS;
+        char **name;
+        const char *method;
+        sd_bus *bus;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        if (!arg_clean_what) {
+                arg_clean_what = strv_new("cache", "runtime");
+                if (!arg_clean_what)
+                        return log_oom();
+        }
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        if (!arg_no_block) {
+                r = bus_wait_for_units_new(bus, &w);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to allocate unit waiter: %m");
+        }
+
+        if (streq(argv[0], "clean"))
+                method = "CleanUnit";
+        else if (streq(argv[0], "freeze"))
+                method = "FreezeUnit";
+        else if (streq(argv[0], "thaw"))
+                method = "ThawUnit";
+        else
+                assert_not_reached("Unhandled method");
+
+        STRV_FOREACH(name, names) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+                if (w) {
+                        /* If we shall wait for the cleaning to complete, let's add a ref on the unit first */
+                        r = bus_call_method(bus, bus_systemd_mgr, "RefUnit", &error, NULL, "s", *name);
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r));
+                                if (ret == EXIT_SUCCESS)
+                                        ret = r;
+                                continue;
+                        }
+                }
+
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(m, "s", *name);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                if (streq(method, "CleanUnit")) {
+                        r = sd_bus_message_append_strv(m, arg_clean_what);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_call(bus, m, 0, &error, NULL);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to %s unit %s: %s", argv[0], *name, bus_error_message(&error, r));
+                        if (ret == EXIT_SUCCESS) {
+                                ret = r;
+                                continue;
+                        }
+                }
+
+                if (w) {
+                        r = bus_wait_for_units_add_unit(w, *name, BUS_WAIT_REFFED|BUS_WAIT_FOR_MAINTENANCE_END, NULL, NULL);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to watch unit %s: %m", *name);
+                }
+        }
+
+        r = bus_wait_for_units_run(w);
+        if (r < 0)
+                return log_error_errno(r, "Failed to wait for units: %m");
+        if (r == BUS_WAIT_FAILURE)
+                ret = EXIT_FAILURE;
+
+        return ret;
+}
diff --git a/src/systemctl/systemctl-clean-or-freeze.h b/src/systemctl/systemctl-clean-or-freeze.h
new file mode 100644 (file)
index 0000000..5db9871
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int clean_or_freeze_unit(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c
new file mode 100644 (file)
index 0000000..dd76d8e
--- /dev/null
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "process-util.h"
+#include "reboot-util.h"
+#include "systemctl-compat-halt.h"
+#include "systemctl-compat-telinit.h"
+#include "systemctl-logind.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "utmp-wtmp.h"
+
+static int halt_help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("halt", "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...]%s\n"
+               "\n%s%s the system.%s\n"
+               "\nOptions:\n"
+               "     --help      Show this help\n"
+               "     --halt      Halt the machine\n"
+               "  -p --poweroff  Switch off the machine\n"
+               "     --reboot    Reboot the machine\n"
+               "  -f --force     Force immediate halt/power-off/reboot\n"
+               "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
+               "  -d --no-wtmp   Don't write wtmp record\n"
+               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , arg_action == ACTION_REBOOT   ? " [ARG]" : ""
+               , ansi_highlight()
+               , arg_action == ACTION_REBOOT   ? "Reboot" :
+                 arg_action == ACTION_POWEROFF ? "Power off" :
+                                                 "Halt"
+               , ansi_normal()
+               , link
+        );
+
+        return 0;
+}
+
+int halt_parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_HELP = 0x100,
+                ARG_HALT,
+                ARG_REBOOT,
+                ARG_NO_WALL
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, ARG_HELP    },
+                { "halt",      no_argument,       NULL, ARG_HALT    },
+                { "poweroff",  no_argument,       NULL, 'p'         },
+                { "reboot",    no_argument,       NULL, ARG_REBOOT  },
+                { "force",     no_argument,       NULL, 'f'         },
+                { "wtmp-only", no_argument,       NULL, 'w'         },
+                { "no-wtmp",   no_argument,       NULL, 'd'         },
+                { "no-sync",   no_argument,       NULL, 'n'         },
+                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
+                {}
+        };
+
+        int c, r, runlevel;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        if (utmp_get_runlevel(&runlevel, NULL) >= 0)
+                if (IN_SET(runlevel, '0', '6'))
+                        arg_force = 2;
+
+        while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_HELP:
+                        return halt_help();
+
+                case ARG_HALT:
+                        arg_action = ACTION_HALT;
+                        break;
+
+                case 'p':
+                        if (arg_action != ACTION_REBOOT)
+                                arg_action = ACTION_POWEROFF;
+                        break;
+
+                case ARG_REBOOT:
+                        arg_action = ACTION_REBOOT;
+                        break;
+
+                case 'f':
+                        arg_force = 2;
+                        break;
+
+                case 'w':
+                        arg_dry_run = true;
+                        break;
+
+                case 'd':
+                        arg_no_wtmp = true;
+                        break;
+
+                case 'n':
+                        arg_no_sync = true;
+                        break;
+
+                case ARG_NO_WALL:
+                        arg_no_wall = true;
+                        break;
+
+                case 'i':
+                case 'h':
+                        /* Compatibility nops */
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
+                r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
+                if (r < 0)
+                        return r;
+        } else if (optind < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Too many arguments.");
+
+        return 1;
+}
+
+int halt_main(void) {
+        int r;
+
+        r = logind_check_inhibitors(arg_action);
+        if (r < 0)
+                return r;
+
+        /* Delayed shutdown requested, and was successful */
+        if (arg_when > 0 && logind_schedule_shutdown() == 0)
+                return 0;
+
+        /* No delay, or logind failed or is not at all available */
+        if (geteuid() != 0) {
+                if (arg_dry_run || arg_force > 0) {
+                        (void) must_be_root();
+                        return -EPERM;
+                }
+
+                /* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to
+                 * shutdown the machine. */
+                if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
+                        r = logind_reboot(arg_action);
+                        if (r >= 0)
+                                return r;
+                        if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+                                /* Requested operation is not supported on the local system or already in
+                                 * progress */
+                                return r;
+
+                        /* on all other errors, try low-level operation */
+                }
+        }
+
+        /* In order to minimize the difference between operation with and without logind, we explicitly
+         * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
+        arg_no_block = true;
+
+        if (!arg_dry_run && !arg_force)
+                return start_with_fallback();
+
+        assert(geteuid() == 0);
+
+        if (!arg_no_wtmp) {
+                if (sd_booted() > 0)
+                        log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
+                else {
+                        r = utmp_put_shutdown();
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to write utmp record: %m");
+                }
+        }
+
+        if (arg_dry_run)
+                return 0;
+
+        r = halt_now(arg_action);
+        return log_error_errno(r, "Failed to reboot: %m");
+}
diff --git a/src/systemctl/systemctl-compat-halt.h b/src/systemctl/systemctl-compat-halt.h
new file mode 100644 (file)
index 0000000..da89aa5
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int halt_parse_argv(int argc, char *argv[]);
+
+int halt_main(void);
diff --git a/src/systemctl/systemctl-compat-runlevel.c b/src/systemctl/systemctl-compat-runlevel.c
new file mode 100644 (file)
index 0000000..39dbba8
--- /dev/null
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "systemctl-compat-runlevel.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "utmp-wtmp.h"
+
+static int runlevel_help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("runlevel", "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...]\n"
+               "\n%sPrints the previous and current runlevel of the init system.%s\n"
+               "\nOptions:\n"
+               "     --help      Show this help\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , ansi_highlight(), ansi_normal()
+               , link
+        );
+
+        return 0;
+}
+
+int runlevel_parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_HELP = 0x100,
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, ARG_HELP    },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_HELP:
+                        return runlevel_help();
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        if (optind < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Too many arguments.");
+
+        return 1;
+}
+
+int runlevel_main(void) {
+        int r, runlevel, previous;
+
+        r = utmp_get_runlevel(&runlevel, &previous);
+        if (r < 0) {
+                puts("unknown");
+                return r;
+        }
+
+        printf("%c %c\n",
+               previous <= 0 ? 'N' : previous,
+               runlevel <= 0 ? 'N' : runlevel);
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-compat-runlevel.h b/src/systemctl/systemctl-compat-runlevel.h
new file mode 100644 (file)
index 0000000..5c89f3d
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int runlevel_parse_argv(int argc, char *argv[]);
+
+int runlevel_main(void);
diff --git a/src/systemctl/systemctl-compat-shutdown.c b/src/systemctl/systemctl-compat-shutdown.c
new file mode 100644 (file)
index 0000000..aca90c9
--- /dev/null
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "systemctl-compat-shutdown.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int shutdown_help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("shutdown", "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...] [TIME] [WALL...]\n"
+               "\n%sShut down the system.%s\n"
+               "\nOptions:\n"
+               "     --help      Show this help\n"
+               "  -H --halt      Halt the machine\n"
+               "  -P --poweroff  Power-off the machine\n"
+               "  -r --reboot    Reboot the machine\n"
+               "  -h             Equivalent to --poweroff, overridden by --halt\n"
+               "  -k             Don't halt/power-off/reboot, just send warnings\n"
+               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
+               "  -c             Cancel a pending shutdown\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , ansi_highlight(), ansi_normal()
+               , link
+        );
+
+        return 0;
+}
+
+int shutdown_parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_HELP = 0x100,
+                ARG_NO_WALL
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, ARG_HELP    },
+                { "halt",      no_argument,       NULL, 'H'         },
+                { "poweroff",  no_argument,       NULL, 'P'         },
+                { "reboot",    no_argument,       NULL, 'r'         },
+                { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
+                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
+                {}
+        };
+
+        char **wall = NULL;
+        int c, r;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_HELP:
+                        return shutdown_help();
+
+                case 'H':
+                        arg_action = ACTION_HALT;
+                        break;
+
+                case 'P':
+                        arg_action = ACTION_POWEROFF;
+                        break;
+
+                case 'r':
+                        if (kexec_loaded())
+                                arg_action = ACTION_KEXEC;
+                        else
+                                arg_action = ACTION_REBOOT;
+                        break;
+
+                case 'K':
+                        arg_action = ACTION_KEXEC;
+                        break;
+
+                case 'h':
+                        if (arg_action != ACTION_HALT)
+                                arg_action = ACTION_POWEROFF;
+                        break;
+
+                case 'k':
+                        arg_dry_run = true;
+                        break;
+
+                case ARG_NO_WALL:
+                        arg_no_wall = true;
+                        break;
+
+                case 'a':
+                case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
+                case 'f':
+                case 'F':
+                        /* Compatibility nops */
+                        break;
+
+                case 'c':
+                        arg_action = ACTION_CANCEL_SHUTDOWN;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
+                r = parse_shutdown_time_spec(argv[optind], &arg_when);
+                if (r < 0) {
+                        log_error("Failed to parse time specification: %s", argv[optind]);
+                        return r;
+                }
+        } else
+                arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
+
+        if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
+                /* No time argument for shutdown cancel */
+                wall = argv + optind;
+        else if (argc > optind + 1)
+                /* We skip the time argument */
+                wall = argv + optind + 1;
+
+        if (wall) {
+                arg_wall = strv_copy(wall);
+                if (!arg_wall)
+                        return log_oom();
+        }
+
+        optind = argc;
+
+        return 1;
+}
diff --git a/src/systemctl/systemctl-compat-shutdown.h b/src/systemctl/systemctl-compat-shutdown.h
new file mode 100644 (file)
index 0000000..79a317d
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int shutdown_parse_argv(int argc, char *argv[]);
diff --git a/src/systemctl/systemctl-compat-telinit.c b/src/systemctl/systemctl-compat-telinit.c
new file mode 100644 (file)
index 0000000..35437ab
--- /dev/null
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "systemctl-compat-telinit.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int telinit_help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("telinit", "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...] COMMAND\n\n"
+               "%sSend control commands to the init daemon.%s\n"
+               "\nCommands:\n"
+               "  0              Power-off the machine\n"
+               "  6              Reboot the machine\n"
+               "  2, 3, 4, 5     Start runlevelX.target unit\n"
+               "  1, s, S        Enter rescue mode\n"
+               "  q, Q           Reload init daemon configuration\n"
+               "  u, U           Reexecute init daemon\n"
+               "\nOptions:\n"
+               "     --help      Show this help\n"
+               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , ansi_highlight(), ansi_normal()
+               , link
+        );
+
+        return 0;
+}
+
+int telinit_parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_HELP = 0x100,
+                ARG_NO_WALL
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, ARG_HELP    },
+                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
+                {}
+        };
+
+        static const struct {
+                char from;
+                enum action to;
+        } table[] = {
+                { '0', ACTION_POWEROFF },
+                { '6', ACTION_REBOOT },
+                { '1', ACTION_RESCUE },
+                { '2', ACTION_RUNLEVEL2 },
+                { '3', ACTION_RUNLEVEL3 },
+                { '4', ACTION_RUNLEVEL4 },
+                { '5', ACTION_RUNLEVEL5 },
+                { 's', ACTION_RESCUE },
+                { 'S', ACTION_RESCUE },
+                { 'q', ACTION_RELOAD },
+                { 'Q', ACTION_RELOAD },
+                { 'u', ACTION_REEXEC },
+                { 'U', ACTION_REEXEC }
+        };
+
+        unsigned i;
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_HELP:
+                        return telinit_help();
+
+                case ARG_NO_WALL:
+                        arg_no_wall = true;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        if (optind >= argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s: required argument missing.",
+                                       program_invocation_short_name);
+
+        if (optind + 1 < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Too many arguments.");
+
+        if (strlen(argv[optind]) != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Expected single character argument.");
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (table[i].from == argv[optind][0])
+                        break;
+
+        if (i >= ELEMENTSOF(table))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Unknown command '%s'.", argv[optind]);
+
+        arg_action = table[i].to;
+
+        optind++;
+
+        return 1;
+}
+
+int start_with_fallback(void) {
+        /* First, try systemd via D-Bus. */
+        if (start_unit(0, NULL, NULL) == 0)
+                return 0;
+
+#if HAVE_SYSV_COMPAT
+        /* Nothing else worked, so let's try /dev/initctl */
+        if (talk_initctl(action_to_runlevel()) > 0)
+                return 0;
+#endif
+
+        return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                               "Failed to talk to init daemon.");
+}
+
+int reload_with_fallback(void) {
+        /* First, try systemd via D-Bus. */
+        if (daemon_reload(0, NULL, NULL) >= 0)
+                return 0;
+
+        /* Nothing else worked, so let's try signals */
+        assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
+
+        if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
+                return log_error_errno(errno, "kill() failed: %m");
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-compat-telinit.h b/src/systemctl/systemctl-compat-telinit.h
new file mode 100644 (file)
index 0000000..ed3e08e
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int telinit_parse_argv(int argc, char *argv[]);
+int start_with_fallback(void);
+int reload_with_fallback(void);
diff --git a/src/systemctl/systemctl-daemon-reload.c b/src/systemctl/systemctl-daemon-reload.c
new file mode 100644 (file)
index 0000000..6730877
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int daemon_reload(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        const char *method;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        switch (arg_action) {
+
+        case ACTION_RELOAD:
+                method = "Reload";
+                break;
+
+        case ACTION_REEXEC:
+                method = "Reexecute";
+                break;
+
+        case ACTION_SYSTEMCTL:
+                method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
+                                     /* "daemon-reload" */ "Reload";
+                break;
+
+        default:
+                assert_not_reached("Unexpected action");
+        }
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are
+         * rerun which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the
+         * generators can have their timeout, and for everything else there's the same time budget in
+         * place. */
+
+        r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+
+        /* On reexecution, we expect a disconnect, not a reply */
+        if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
+                r = 0;
+
+        if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+                return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+        /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support
+         * fallbacks to the old ways of doing things, hence don't log any error in that case here. */
+
+        return r < 0 ? r : 0;
+}
diff --git a/src/systemctl/systemctl-daemon-reload.h b/src/systemctl/systemctl-daemon-reload.h
new file mode 100644 (file)
index 0000000..01fd500
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int daemon_reload(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c
new file mode 100644 (file)
index 0000000..d6f595d
--- /dev/null
@@ -0,0 +1,592 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "copy.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "pager.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "process-util.h"
+#include "selinux-util.h"
+#include "stat-util.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-edit.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "tmpfile-util.h"
+
+#define EDIT_MARKER_START "### Anything between here and the comment below will become the new contents of the file"
+#define EDIT_MARKER_END "### Lines below this comment will be discarded"
+
+int cat(int argc, char *argv[], void *userdata) {
+        _cleanup_(hashmap_freep) Hashmap *cached_name_map = NULL, *cached_id_map = NULL;
+        _cleanup_(lookup_paths_free) LookupPaths lp = {};
+        _cleanup_strv_free_ char **names = NULL;
+        char **name;
+        sd_bus *bus;
+        bool first = true;
+        int r, rc = 0;
+
+        /* Include all units by default — i.e. continue as if the --all option was used */
+        if (strv_isempty(arg_states))
+                arg_all = true;
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
+
+        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine unit paths: %m");
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        r = maybe_extend_with_unit_dependencies(bus, &names);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        STRV_FOREACH(name, names) {
+                _cleanup_free_ char *fragment_path = NULL;
+                _cleanup_strv_free_ char **dropin_paths = NULL;
+
+                r = unit_find_paths(bus, *name, &lp, false, &cached_name_map, &cached_id_map, &fragment_path, &dropin_paths);
+                if (r == -ERFKILL) {
+                        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());
+                        continue;
+                }
+                if (r < 0)
+                        return r;
+                if (r == 0) {
+                        /* Skip units which have no on-disk counterpart, but propagate the error to the
+                         * user */
+                        rc = -ENOENT;
+                        continue;
+                }
+
+                if (first)
+                        first = false;
+                else
+                        puts("");
+
+                if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
+                        fprintf(stderr,
+                                "%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
+                                "%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
+                                "%s# If fragments or drop-ins were added or removed, they are not properly reflected in this output.\n"
+                                "%s# Run 'systemctl%s daemon-reload' to reload units.%s\n",
+                                ansi_highlight_red(),
+                                *name,
+                                ansi_highlight_red(),
+                                ansi_highlight_red(),
+                                ansi_highlight_red(),
+                                arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+                                ansi_normal());
+
+                r = cat_files(fragment_path, dropin_paths, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        return rc;
+}
+
+static int create_edit_temp_file(const char *new_path, const char *original_path, char ** const original_unit_paths, char **ret_tmp_fn) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert(new_path);
+        assert(ret_tmp_fn);
+
+        r = tempfn_random(new_path, NULL, &t);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
+
+        r = mkdir_parents_label(new_path, 0755);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
+
+        if (original_path) {
+                r = mac_selinux_create_file_prepare(new_path, S_IFREG);
+                if (r < 0)
+                        return r;
+
+                r = copy_file(original_path, t, 0, 0644, 0, 0, COPY_REFLINK);
+                if (r == -ENOENT) {
+                        r = touch(t);
+                        mac_selinux_create_file_clear();
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+                } else {
+                        mac_selinux_create_file_clear();
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
+                }
+        } else if (original_unit_paths) {
+                _cleanup_free_ char *new_contents = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
+                char **path;
+                size_t size;
+
+                r = mac_selinux_create_file_prepare(new_path, S_IFREG);
+                if (r < 0)
+                        return r;
+
+                f = fopen(t, "we");
+                mac_selinux_create_file_clear();
+                if (!f)
+                        return log_error_errno(errno, "Failed to open \"%s\": %m", t);
+
+                r = fchmod(fileno(f), 0644);
+                if (r < 0)
+                        return log_error_errno(errno, "Failed to change mode of \"%s\": %m", t);
+
+                r = read_full_file(new_path, &new_contents, &size);
+                if (r < 0 && r != -ENOENT)
+                        return log_error_errno(r, "Failed to read \"%s\": %m", new_path);
+
+                fprintf(f,
+                        "### Editing %s\n"
+                        EDIT_MARKER_START
+                        "\n\n%s%s\n"
+                        EDIT_MARKER_END,
+                        new_path,
+                        strempty(new_contents),
+                        new_contents && endswith(new_contents, "\n") ? "" : "\n");
+
+                /* Add a comment with the contents of the original unit files */
+                STRV_FOREACH(path, original_unit_paths) {
+                        _cleanup_free_ char *contents = NULL;
+
+                        /* Skip the file that's being edited */
+                        if (path_equal(*path, new_path))
+                                continue;
+
+                        r = read_full_file(*path, &contents, &size);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to read \"%s\": %m", *path);
+
+                        fprintf(f, "\n\n### %s", *path);
+                        if (!isempty(contents)) {
+                                contents = strreplace(strstrip(contents), "\n", "\n# ");
+                                if (!contents)
+                                        return log_oom();
+                                fprintf(f, "\n# %s", contents);
+                        }
+                }
+
+                r = fflush_and_check(f);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+        }
+
+        *ret_tmp_fn = TAKE_PTR(t);
+
+        return 0;
+}
+
+static int get_file_to_edit(
+                const LookupPaths *paths,
+                const char *name,
+                char **ret_path) {
+
+        _cleanup_free_ char *path = NULL, *run = NULL;
+
+        assert(name);
+        assert(ret_path);
+
+        path = path_join(paths->persistent_config, name);
+        if (!path)
+                return log_oom();
+
+        if (arg_runtime) {
+                run = path_join(paths->runtime_config, name);
+                if (!run)
+                        return log_oom();
+        }
+
+        if (arg_runtime) {
+                if (access(path, F_OK) >= 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                               "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
+                                               run, path);
+
+                *ret_path = TAKE_PTR(run);
+        } else
+                *ret_path = TAKE_PTR(path);
+
+        return 0;
+}
+
+static int unit_file_create_new(
+                const LookupPaths *paths,
+                const char *unit_name,
+                const char *suffix,
+                char ** const original_unit_paths,
+                char **ret_new_path,
+                char **ret_tmp_path) {
+
+        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
+        const char *ending;
+        int r;
+
+        assert(unit_name);
+        assert(ret_new_path);
+        assert(ret_tmp_path);
+
+        ending = strjoina(unit_name, suffix);
+        r = get_file_to_edit(paths, ending, &new_path);
+        if (r < 0)
+                return r;
+
+        r = create_edit_temp_file(new_path, NULL, original_unit_paths, &tmp_path);
+        if (r < 0)
+                return r;
+
+        *ret_new_path = TAKE_PTR(new_path);
+        *ret_tmp_path = TAKE_PTR(tmp_path);
+
+        return 0;
+}
+
+static int unit_file_create_copy(
+                const LookupPaths *paths,
+                const char *unit_name,
+                const char *fragment_path,
+                char **ret_new_path,
+                char **ret_tmp_path) {
+
+        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
+        int r;
+
+        assert(fragment_path);
+        assert(unit_name);
+        assert(ret_new_path);
+        assert(ret_tmp_path);
+
+        r = get_file_to_edit(paths, unit_name, &new_path);
+        if (r < 0)
+                return r;
+
+        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] ", new_path, fragment_path);
+                if (r < 0)
+                        return r;
+                if (response != 'y')
+                        return log_warning_errno(SYNTHETIC_ERRNO(EKEYREJECTED), "%s skipped.", unit_name);
+        }
+
+        r = create_edit_temp_file(new_path, fragment_path, NULL, &tmp_path);
+        if (r < 0)
+                return r;
+
+        *ret_new_path = TAKE_PTR(new_path);
+        *ret_tmp_path = TAKE_PTR(tmp_path);
+
+        return 0;
+}
+
+static int run_editor(char **paths) {
+        int r;
+
+        assert(paths);
+
+        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) {
+                char **editor_args = NULL, **tmp_path, **original_path;
+                size_t n_editor_args = 0, i = 1, argc;
+                const char **args, *editor, *p;
+
+                argc = strv_length(paths)/2 + 1;
+
+                /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL.  If
+                 * neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present, we try to execute well known
+                 * editors. */
+                editor = getenv("SYSTEMD_EDITOR");
+                if (!editor)
+                        editor = getenv("EDITOR");
+                if (!editor)
+                        editor = getenv("VISUAL");
+
+                if (!isempty(editor)) {
+                        editor_args = strv_split(editor, WHITESPACE);
+                        if (!editor_args) {
+                                (void) log_oom();
+                                _exit(EXIT_FAILURE);
+                        }
+                        n_editor_args = strv_length(editor_args);
+                        argc += n_editor_args - 1;
+                }
+
+                args = newa(const char*, argc + 1);
+
+                if (n_editor_args > 0) {
+                        args[0] = editor_args[0];
+                        for (; i < n_editor_args; i++)
+                                args[i] = editor_args[i];
+                }
+
+                STRV_FOREACH_PAIR(original_path, tmp_path, paths)
+                        args[i++] = *tmp_path;
+                args[i] = NULL;
+
+                if (n_editor_args > 0)
+                        execvp(args[0], (char* const*) args);
+
+                FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
+                        args[0] = p;
+                        execvp(p, (char* const*) args);
+                        /* We do not fail if the editor doesn't exist because we want to try each one of them
+                         * before failing. */
+                        if (errno != ENOENT) {
+                                log_error_errno(errno, "Failed to execute %s: %m", editor);
+                                _exit(EXIT_FAILURE);
+                        }
+                }
+
+                log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
+                _exit(EXIT_FAILURE);
+        }
+
+        return 0;
+}
+
+static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
+        _cleanup_(hashmap_freep) Hashmap *cached_name_map = NULL, *cached_id_map = NULL;
+        _cleanup_(lookup_paths_free) LookupPaths lp = {};
+        char **name;
+        int r;
+
+        assert(names);
+        assert(paths);
+
+        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(name, names) {
+                _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL, *tmp_name = NULL;
+                _cleanup_strv_free_ char **unit_paths = NULL;
+                const char *unit_name;
+
+                r = unit_find_paths(bus, *name, &lp, false, &cached_name_map, &cached_id_map, &path, &unit_paths);
+                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, &cached_name_map, &cached_id_map, &path, NULL);
+                }
+                if (r == -ERFKILL)
+                        return log_error_errno(r, "Unit '%s' masked, cannot edit.", *name);
+                if (r < 0)
+                        return r;
+
+                if (r == 0) {
+                        assert(!path);
+
+                        if (!arg_force) {
+                                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;
+                        }
+
+                        /* Create a new unit from scratch */
+                        unit_name = *name;
+                        r = unit_file_create_new(&lp, unit_name,
+                                                 arg_full ? NULL : ".d/override.conf",
+                                                 NULL, &new_path, &tmp_path);
+                } else {
+                        assert(path);
+
+                        unit_name = basename(path);
+                        /* We follow unit aliases, but we need to propagate the instance */
+                        if (unit_name_is_valid(*name, UNIT_NAME_INSTANCE) &&
+                            unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+                                _cleanup_free_ char *instance = NULL;
+
+                                r = unit_name_to_instance(*name, &instance);
+                                if (r < 0)
+                                        return r;
+
+                                r = unit_name_replace_instance(unit_name, instance, &tmp_name);
+                                if (r < 0)
+                                        return r;
+
+                                unit_name = tmp_name;
+                        }
+
+                        if (arg_full)
+                                r = unit_file_create_copy(&lp, unit_name, path, &new_path, &tmp_path);
+                        else {
+                                r = strv_prepend(&unit_paths, path);
+                                if (r < 0)
+                                        return log_oom();
+
+                                r = unit_file_create_new(&lp, unit_name, ".d/override.conf", unit_paths, &new_path, &tmp_path);
+                        }
+                }
+                if (r < 0)
+                        return r;
+
+                r = strv_push_pair(paths, new_path, tmp_path);
+                if (r < 0)
+                        return log_oom();
+
+                new_path = tmp_path = NULL;
+        }
+
+        return 0;
+}
+
+static int trim_edit_markers(const char *path) {
+        _cleanup_free_ char *contents = NULL;
+        char *contents_start = NULL;
+        const char *contents_end = NULL;
+        size_t size;
+        int r;
+
+        /* Trim out the lines between the two markers */
+        r = read_full_file(path, &contents, &size);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read temporary file \"%s\": %m", path);
+
+        contents_start = strstr(contents, EDIT_MARKER_START);
+        if (contents_start)
+                contents_start += strlen(EDIT_MARKER_START);
+        else
+                contents_start = contents;
+
+        contents_end = strstr(contents_start, EDIT_MARKER_END);
+        if (contents_end)
+                strshorten(contents_start, contents_end - contents_start);
+
+        contents_start = strstrip(contents_start);
+
+        /* Write new contents if the trimming actually changed anything */
+        if (strlen(contents) != size) {
+                r = write_string_file(path, contents_start, WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_TRUNCATE | WRITE_STRING_FILE_AVOID_NEWLINE);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to modify temporary file \"%s\": %m", path);
+        }
+
+        return 0;
+}
+
+int edit(int argc, char *argv[], void *userdata) {
+        _cleanup_(lookup_paths_free) LookupPaths lp = {};
+        _cleanup_strv_free_ char **names = NULL;
+        _cleanup_strv_free_ char **paths = NULL;
+        char **original, **tmp;
+        sd_bus *bus;
+        int r;
+
+        if (!on_tty())
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units if not on a tty.");
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely.");
+
+        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine unit paths: %m");
+
+        r = mac_selinux_init();
+        if (r < 0)
+                return r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        STRV_FOREACH(tmp, names) {
+                r = unit_is_masked(bus, &lp, *tmp);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit %s: unit is masked.", *tmp);
+        }
+
+        r = find_paths_to_edit(bus, names, &paths);
+        if (r < 0)
+                return r;
+
+        if (strv_isempty(paths))
+                return -ENOENT;
+
+        r = run_editor(paths);
+        if (r < 0)
+                goto end;
+
+        STRV_FOREACH_PAIR(original, tmp, paths) {
+                /* If the temporary file is empty we ignore it. This allows the user to cancel the
+                 * modification. */
+                r = trim_edit_markers(*tmp);
+                if (r < 0)
+                        continue;
+
+                if (null_or_empty_path(*tmp)) {
+                        log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
+                        continue;
+                }
+
+                r = rename(*tmp, *original);
+                if (r < 0) {
+                        r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
+                        goto end;
+                }
+        }
+
+        r = 0;
+
+        if (!arg_no_reload && !install_client_side())
+                r = daemon_reload(argc, argv, userdata);
+
+end:
+        STRV_FOREACH_PAIR(original, tmp, paths) {
+                (void) unlink(*tmp);
+
+                /* Removing empty dropin dirs */
+                if (!arg_full) {
+                        _cleanup_free_ char *dir;
+
+                        dir = dirname_malloc(*original);
+                        if (!dir)
+                                return log_oom();
+
+                        /* No need to check if the dir is empty, rmdir does nothing if it is not the case. */
+                        (void) rmdir(dir);
+                }
+        }
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-edit.h b/src/systemctl/systemctl-edit.h
new file mode 100644 (file)
index 0000000..98cb942
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int cat(int argc, char *argv[], void *userdata);
+int edit(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c
new file mode 100644 (file)
index 0000000..c9daeb1
--- /dev/null
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "locale-util.h"
+#include "path-util.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-enable.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int normalize_filenames(char **names) {
+        char **u;
+        int r;
+
+        STRV_FOREACH(u, names)
+                if (!path_is_absolute(*u)) {
+                        char* normalized_path;
+
+                        if (!isempty(arg_root))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Non-absolute paths are not allowed when --root is used: %s",
+                                                       *u);
+
+                        if (!strchr(*u,'/'))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Link argument does contain at least one directory separator: %s",
+                                                       *u);
+
+                        r = path_make_absolute_cwd(*u, &normalized_path);
+                        if (r < 0)
+                                return r;
+
+                        free_and_replace(*u, normalized_path);
+                }
+
+        return 0;
+}
+
+static int normalize_names(char **names, bool warn_if_path) {
+        char **u;
+        bool was_path = false;
+
+        STRV_FOREACH(u, names) {
+                int r;
+
+                if (!is_path(*u))
+                        continue;
+
+                r = free_and_strdup(u, basename(*u));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to normalize unit file path: %m");
+
+                was_path = true;
+        }
+
+        if (warn_if_path && was_path)
+                log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
+
+        return 0;
+}
+
+int enable_unit(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **names = NULL;
+        const char *verb = argv[0];
+        UnitFileChange *changes = NULL;
+        size_t n_changes = 0;
+        int carries_install_info = -1;
+        bool ignore_carries_install_info = arg_quiet;
+        int r;
+
+        if (!argv[1])
+                return 0;
+
+        r = mangle_names("to enable", strv_skip(argv, 1), &names);
+        if (r < 0)
+                return r;
+
+        r = enable_sysv_units(verb, names);
+        if (r < 0)
+                return r;
+
+        /* If the operation was fully executed by the SysV compat, let's finish early */
+        if (strv_isempty(names)) {
+                if (arg_no_reload || install_client_side())
+                        return 0;
+                return daemon_reload(argc, argv, userdata);
+        }
+
+        if (streq(verb, "disable")) {
+                r = normalize_names(names, true);
+                if (r < 0)
+                        return r;
+        }
+
+        if (streq(verb, "link")) {
+                r = normalize_filenames(names);
+                if (r < 0)
+                        return r;
+        }
+
+        if (install_client_side()) {
+                UnitFileFlags flags;
+
+                flags = unit_file_flags_from_args();
+                if (streq(verb, "enable")) {
+                        r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                        carries_install_info = r;
+                } else if (streq(verb, "disable"))
+                        r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                else if (streq(verb, "reenable")) {
+                        r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                        carries_install_info = r;
+                } else if (streq(verb, "link"))
+                        r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                else if (streq(verb, "preset")) {
+                        r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
+                } else if (streq(verb, "mask"))
+                        r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                else if (streq(verb, "unmask"))
+                        r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                else if (streq(verb, "revert"))
+                        r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
+                else
+                        assert_not_reached("Unknown verb");
+
+                unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
+                if (r < 0)
+                        goto finish;
+                r = 0;
+        } else {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                bool expect_carries_install_info = false;
+                bool send_runtime = true, send_force = true, send_preset_mode = false;
+                const char *method;
+                sd_bus *bus;
+
+                if (STR_IN_SET(verb, "mask", "unmask")) {
+                        char **name;
+                        _cleanup_(lookup_paths_free) LookupPaths lp = {};
+
+                        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
+                        if (r < 0)
+                                return r;
+
+                        STRV_FOREACH(name, names) {
+                                r = unit_exists(&lp, *name);
+                                if (r < 0)
+                                        return r;
+                                if (r == 0)
+                                        log_notice("Unit %s does not exist, proceeding anyway.", *name);
+                        }
+                }
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                polkit_agent_open_maybe();
+
+                if (streq(verb, "enable")) {
+                        method = "EnableUnitFiles";
+                        expect_carries_install_info = true;
+                } else if (streq(verb, "disable")) {
+                        method = "DisableUnitFiles";
+                        send_force = false;
+                } else if (streq(verb, "reenable")) {
+                        method = "ReenableUnitFiles";
+                        expect_carries_install_info = true;
+                } else if (streq(verb, "link"))
+                        method = "LinkUnitFiles";
+                else if (streq(verb, "preset")) {
+
+                        if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
+                                method = "PresetUnitFilesWithMode";
+                                send_preset_mode = true;
+                        } else
+                                method = "PresetUnitFiles";
+
+                        expect_carries_install_info = true;
+                        ignore_carries_install_info = true;
+                } else if (streq(verb, "mask"))
+                        method = "MaskUnitFiles";
+                else if (streq(verb, "unmask")) {
+                        method = "UnmaskUnitFiles";
+                        send_force = false;
+                } else if (streq(verb, "revert")) {
+                        method = "RevertUnitFiles";
+                        send_runtime = send_force = false;
+                } else
+                        assert_not_reached("Unknown verb");
+
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, names);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                if (send_preset_mode) {
+                        r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                if (send_runtime) {
+                        r = sd_bus_message_append(m, "b", arg_runtime);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                if (send_force) {
+                        r = sd_bus_message_append(m, "b", arg_force);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
+
+                if (expect_carries_install_info) {
+                        r = sd_bus_message_read(reply, "b", &carries_install_info);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+                }
+
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
+                if (r < 0)
+                        goto finish;
+
+                /* Try to reload if enabled */
+                if (!arg_no_reload)
+                        r = daemon_reload(argc, argv, userdata);
+                else
+                        r = 0;
+        }
+
+        if (carries_install_info == 0 && !ignore_carries_install_info)
+                log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
+                           "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
+                           "units). This means they are not meant to be enabled using systemctl.\n"
+                           " \n" /* trick: the space is needed so that the line does not get stripped from output */
+                           "Possible reasons for having this kind of units are:\n"
+                           "%1$s A unit may be statically enabled by being symlinked from another unit's\n"
+                           "  .wants/ or .requires/ directory.\n"
+                           "%1$s A unit's purpose may be to act as a helper for some other unit which has\n"
+                           "  a requirement dependency on it.\n"
+                           "%1$s A unit may be started when needed via activation (socket, path, timer,\n"
+                           "  D-Bus, udev, scripted systemctl call, ...).\n"
+                           "%1$s In case of template units, the unit is meant to be enabled with some\n"
+                           "  instance name specified.",
+                           special_glyph(SPECIAL_GLYPH_BULLET));
+
+        if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
+                sd_bus *bus;
+                size_t len, i;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        goto finish;
+
+                len = strv_length(names);
+                {
+                        char *new_args[len + 2];
+
+                        new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
+                        for (i = 0; i < len; i++)
+                                new_args[i + 1] = basename(names[i]);
+                        new_args[i + 1] = NULL;
+
+                        r = start_unit(len + 1, new_args, userdata);
+                }
+        }
+
+finish:
+        unit_file_changes_free(changes, n_changes);
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-enable.h b/src/systemctl/systemctl-enable.h
new file mode 100644 (file)
index 0000000..33802b4
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int enable_unit(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-is-active.c b/src/systemctl/systemctl-is-active.c
new file mode 100644 (file)
index 0000000..18eba2d
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "pretty-print.h"
+#include "syslog-util.h"
+#include "systemctl-is-active.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
+        _cleanup_strv_free_ char **names = NULL;
+        UnitActiveState active_state;
+        sd_bus *bus;
+        char **name;
+        int r, i;
+        bool found = false;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = expand_unit_names(bus, args, NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        STRV_FOREACH(name, names) {
+                r = get_state_one_unit(bus, *name, &active_state);
+                if (r < 0)
+                        return r;
+
+                if (!arg_quiet)
+                        puts(unit_active_state_to_string(active_state));
+
+                for (i = 0; i < nb_states; ++i)
+                        if (good_states[i] == active_state)
+                                found = true;
+        }
+
+        /* use the given return code for the case that we won't find
+         * any unit which matches the list */
+        return found ? 0 : code;
+}
+
+int check_unit_active(int argc, char *argv[], void *userdata) {
+        static const UnitActiveState states[] = {
+                UNIT_ACTIVE,
+                UNIT_RELOADING,
+        };
+
+        /* According to LSB: 3, "program is not running" */
+        return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
+}
+
+int check_unit_failed(int argc, char *argv[], void *userdata) {
+        static const UnitActiveState states[] = {
+                UNIT_FAILED,
+        };
+
+        return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
+}
diff --git a/src/systemctl/systemctl-is-active.h b/src/systemctl/systemctl-is-active.h
new file mode 100644 (file)
index 0000000..18b0e1d
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int check_unit_active(int argc, char *argv[], void *userdata);
+int check_unit_failed(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c
new file mode 100644 (file)
index 0000000..dd64d2e
--- /dev/null
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-is-enabled.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int show_installation_targets_client_side(const char *name) {
+        UnitFileChange *changes = NULL;
+        size_t n_changes = 0, i;
+        UnitFileFlags flags;
+        char **p;
+        int r;
+
+        p = STRV_MAKE(name);
+        flags = UNIT_FILE_DRY_RUN |
+                (arg_runtime ? UNIT_FILE_RUNTIME : 0);
+
+        r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get file links for %s: %m", name);
+
+        for (i = 0; i < n_changes; i++)
+                if (changes[i].type == UNIT_FILE_UNLINK)
+                        printf("  %s\n", changes[i].path);
+
+        return 0;
+}
+
+static int show_installation_targets(sd_bus *bus, const char *name) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *link;
+        int r;
+
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileLinks", &error, &reply, "sb", name, arg_runtime);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
+                printf("  %s\n", link);
+
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return 0;
+}
+
+int unit_is_enabled(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **names = NULL;
+        bool enabled;
+        char **name;
+        int r;
+
+        r = mangle_names("to check", strv_skip(argv, 1), &names);
+        if (r < 0)
+                return r;
+
+        r = enable_sysv_units(argv[0], names);
+        if (r < 0)
+                return r;
+
+        enabled = r > 0;
+
+        if (install_client_side()) {
+                STRV_FOREACH(name, names) {
+                        UnitFileState state;
+
+                        r = unit_file_get_state(arg_scope, arg_root, *name, &state);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get unit file state for %s: %m", *name);
+
+                        if (IN_SET(state,
+                                   UNIT_FILE_ENABLED,
+                                   UNIT_FILE_ENABLED_RUNTIME,
+                                   UNIT_FILE_STATIC,
+                                   UNIT_FILE_ALIAS,
+                                   UNIT_FILE_INDIRECT,
+                                   UNIT_FILE_GENERATED))
+                                enabled = true;
+
+                        if (!arg_quiet) {
+                                puts(unit_file_state_to_string(state));
+                                if (arg_full) {
+                                        r = show_installation_targets_client_side(*name);
+                                        if (r < 0)
+                                                return r;
+                                }
+                        }
+                }
+
+                r = 0;
+        } else {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus *bus;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(name, names) {
+                        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                        const char *s;
+
+                        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", *name);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
+
+                        r = sd_bus_message_read(reply, "s", &s);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
+                                enabled = true;
+
+                        if (!arg_quiet) {
+                                puts(s);
+                                if (arg_full) {
+                                        r = show_installation_targets(bus, *name);
+                                        if (r < 0)
+                                                return r;
+                                }
+                        }
+                }
+        }
+
+        return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/systemctl/systemctl-is-enabled.h b/src/systemctl/systemctl-is-enabled.h
new file mode 100644 (file)
index 0000000..860153e
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int unit_is_enabled(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-is-system-running.c b/src/systemctl/systemctl-is-system-running.c
new file mode 100644 (file)
index 0000000..96186ee
--- /dev/null
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "sd-event.h"
+#include "sd-daemon.h"
+
+#include "systemctl-util.h"
+#include "systemctl-is-system-running.h"
+#include "virt.h"
+#include "systemctl.h"
+#include "bus-util.h"
+#include "bus-locator.h"
+#include "bus-error.h"
+
+static int match_startup_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        char **state = userdata;
+        int r;
+
+        assert(state);
+
+        r = bus_get_property_string(sd_bus_message_get_bus(m), bus_systemd_mgr, "SystemState", NULL, state);
+
+        sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r);
+        return 0;
+}
+
+int is_system_running(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_startup_finished = NULL;
+        _cleanup_(sd_event_unrefp) sd_event* event = NULL;
+        _cleanup_free_ char *state = NULL;
+        sd_bus *bus;
+        int r;
+
+        if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
+                if (!arg_quiet)
+                        puts("offline");
+                return EXIT_FAILURE;
+        }
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        if (arg_wait) {
+                r = sd_event_default(&event);
+                if (r >= 0)
+                        r = sd_bus_attach_event(bus, event, 0);
+                if (r >= 0)
+                        r = bus_match_signal_async(
+                                        bus,
+                                        &slot_startup_finished,
+                                        bus_systemd_mgr,
+                                        "StartupFinished",
+                                        match_startup_finished, NULL, &state);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to request match for StartupFinished: %m");
+                        arg_wait = false;
+                }
+        }
+
+        r = bus_get_property_string(bus, bus_systemd_mgr, "SystemState", &error, &state);
+        if (r < 0) {
+                log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r));
+
+                if (!arg_quiet)
+                        puts("unknown");
+                return EXIT_FAILURE;
+        }
+
+        if (arg_wait && STR_IN_SET(state, "initializing", "starting")) {
+                r = sd_event_loop(event);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to get property from event loop: %m");
+                        if (!arg_quiet)
+                                puts("unknown");
+                        return EXIT_FAILURE;
+                }
+        }
+
+        if (!arg_quiet)
+                puts(state);
+
+        return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/systemctl/systemctl-is-system-running.h b/src/systemctl/systemctl-is-system-running.h
new file mode 100644 (file)
index 0000000..c955f32
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int is_system_running(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-kill.c b/src/systemctl/systemctl-kill.c
new file mode 100644 (file)
index 0000000..258546f
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-kill.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int kill_unit(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **names = NULL;
+        char *kill_who = NULL, **name;
+        sd_bus *bus;
+        int r, q;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        if (!arg_kill_who)
+                arg_kill_who = "all";
+
+        /* --fail was specified */
+        if (streq(arg_job_mode, "fail"))
+                kill_who = strjoina(arg_kill_who, "-fail");
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        STRV_FOREACH(name, names) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                q = bus_call_method(
+                                bus,
+                                bus_systemd_mgr,
+                                "KillUnit",
+                                &error,
+                                NULL,
+                                "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
+                if (q < 0) {
+                        log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
+                        if (r == 0)
+                                r = q;
+                }
+        }
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-kill.h b/src/systemctl/systemctl-kill.h
new file mode 100644 (file)
index 0000000..d904612
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int kill_unit(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-list-dependencies.c b/src/systemctl/systemctl-list-dependencies.c
new file mode 100644 (file)
index 0000000..9aedcc5
--- /dev/null
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "locale-util.h"
+#include "sort-util.h"
+#include "special.h"
+#include "systemctl-list-dependencies.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int list_dependencies_print(const char *name, int level, unsigned branches, bool last) {
+        _cleanup_free_ char *n = NULL;
+        size_t max_len = MAX(columns(),20u);
+        size_t len = 0;
+        int i;
+
+        if (!arg_plain) {
+
+                for (i = level - 1; i >= 0; i--) {
+                        len += 2;
+                        if (len > max_len - 3 && !arg_full) {
+                                printf("%s...\n",max_len % 2 ? "" : " ");
+                                return 0;
+                        }
+                        printf("%s", special_glyph(branches & (1 << i) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
+                }
+                len += 2;
+
+                if (len > max_len - 3 && !arg_full) {
+                        printf("%s...\n",max_len % 2 ? "" : " ");
+                        return 0;
+                }
+
+                printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
+        }
+
+        if (arg_full) {
+                printf("%s\n", name);
+                return 0;
+        }
+
+        n = ellipsize(name, max_len-len, 100);
+        if (!n)
+                return log_oom();
+
+        printf("%s\n", n);
+        return 0;
+}
+
+static int list_dependencies_compare(char * const *a, char * const *b) {
+        if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
+                return 1;
+        if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
+                return -1;
+
+        return strcasecmp(*a, *b);
+}
+
+static int list_dependencies_one(
+                sd_bus *bus,
+                const char *name,
+                int level,
+                char ***units,
+                unsigned branches) {
+
+        _cleanup_strv_free_ char **deps = NULL;
+        char **c;
+        int r;
+
+        assert(bus);
+        assert(name);
+        assert(units);
+
+        r = strv_extend(units, name);
+        if (r < 0)
+                return log_oom();
+
+        r = unit_get_dependencies(bus, name, &deps);
+        if (r < 0)
+                return r;
+
+        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
+
+        STRV_FOREACH(c, deps) {
+                if (strv_contains(*units, *c)) {
+                        if (!arg_plain) {
+                                printf("  ");
+                                r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
+                                if (r < 0)
+                                        return r;
+                        }
+                        continue;
+                }
+
+                if (arg_plain)
+                        printf("  ");
+                else {
+                        UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
+                        const char *on;
+
+                        (void) get_state_one_unit(bus, *c, &active_state);
+
+                        switch (active_state) {
+                        case UNIT_ACTIVE:
+                        case UNIT_RELOADING:
+                        case UNIT_ACTIVATING:
+                                on = ansi_highlight_green();
+                                break;
+
+                        case UNIT_INACTIVE:
+                        case UNIT_DEACTIVATING:
+                                on = ansi_normal();
+                                break;
+
+                        default:
+                                on = ansi_highlight_red();
+                                break;
+                        }
+
+                        printf("%s%s%s ", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), ansi_normal());
+                }
+
+                r = list_dependencies_print(*c, level, branches, c[1] == NULL);
+                if (r < 0)
+                        return r;
+
+                if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
+                       r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
+                       if (r < 0)
+                               return r;
+                }
+        }
+
+        if (!arg_plain)
+                strv_remove(*units, name);
+
+        return 0;
+}
+
+int list_dependencies(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **units = NULL, **done = NULL;
+        char **u, **patterns;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        patterns = strv_skip(argv, 1);
+        if (strv_isempty(patterns)) {
+                units = strv_new(SPECIAL_DEFAULT_TARGET);
+                if (!units)
+                        return log_oom();
+        } else {
+                r = expand_unit_names(bus, patterns, NULL, &units, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to expand names: %m");
+        }
+
+        (void) pager_open(arg_pager_flags);
+
+        STRV_FOREACH(u, units) {
+                if (u != units)
+                        puts("");
+
+                puts(*u);
+                r = list_dependencies_one(bus, *u, 0, &done, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-list-dependencies.h b/src/systemctl/systemctl-list-dependencies.h
new file mode 100644 (file)
index 0000000..cdc7fc2
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int list_dependencies(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-list-jobs.c b/src/systemctl/systemctl-list-jobs.c
new file mode 100644 (file)
index 0000000..64a8d67
--- /dev/null
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "locale-util.h"
+#include "systemctl-list-jobs.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const char *method, const char *prefix) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        const char *name, *type;
+        uint32_t other_id;
+        int r;
+
+        assert(bus);
+
+        r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
+
+        r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
+                _cleanup_free_ char *row = NULL;
+                int rc;
+
+                if (asprintf(&row, "%s %u (%s/%s)", prefix, other_id, name, type) < 0)
+                        return log_oom();
+
+                rc = table_add_many(table,
+                                    TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
+                                    TABLE_STRING, row,
+                                    TABLE_EMPTY,
+                                    TABLE_EMPTY);
+                if (rc < 0)
+                        return table_log_add_error(r);
+        }
+
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return 0;
+}
+
+struct job_info {
+        uint32_t id;
+        const char *name, *type, *state;
+};
+
+static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        const struct job_info *j;
+        const char *on, *off;
+        int r;
+
+        assert(n == 0 || jobs);
+
+        if (n == 0) {
+                if (!arg_no_legend) {
+                        on = ansi_highlight_green();
+                        off = ansi_normal();
+
+                        printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
+                }
+                return 0;
+        }
+
+        (void) pager_open(arg_pager_flags);
+
+        table = table_new("job", "unit", "type", "state");
+        if (!table)
+                return log_oom();
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        for (j = jobs; j < jobs + n; j++) {
+                if (streq(j->state, "running"))
+                        on = ansi_highlight();
+                else
+                        on =  "";
+
+                r = table_add_many(table,
+                                   TABLE_UINT, j->id,
+                                   TABLE_STRING, j->name,
+                                   TABLE_SET_COLOR, on,
+                                   TABLE_STRING, j->type,
+                                   TABLE_STRING, j->state,
+                                   TABLE_SET_COLOR, on);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (arg_jobs_after)
+                        output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
+                if (arg_jobs_before)
+                        output_waiting_jobs(bus, table, j->id, "GetJobBefore", "\tblocking job");
+        }
+
+        r = table_print(table, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to print the table: %m");
+
+        if (!arg_no_legend) {
+                on = ansi_highlight();
+                off = ansi_normal();
+
+                printf("\n%s%u jobs listed%s.\n", on, n, off);
+        }
+
+        return 0;
+}
+
+static bool output_show_job(struct job_info *job, char **patterns) {
+        return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
+}
+
+int list_jobs(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ struct job_info *jobs = NULL;
+        const char *name, *type, *state;
+        bool skipped = false;
+        size_t size = 0;
+        unsigned c = 0;
+        sd_bus *bus;
+        uint32_t id;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, NULL, NULL)) > 0) {
+                struct job_info job = { id, name, type, state };
+
+                if (!output_show_job(&job, strv_skip(argv, 1))) {
+                        skipped = true;
+                        continue;
+                }
+
+                if (!GREEDY_REALLOC(jobs, size, c + 1))
+                        return log_oom();
+
+                jobs[c++] = job;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        (void) pager_open(arg_pager_flags);
+
+        return output_jobs_list(bus, jobs, c, skipped);
+}
diff --git a/src/systemctl/systemctl-list-jobs.h b/src/systemctl/systemctl-list-jobs.h
new file mode 100644 (file)
index 0000000..40d6e83
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int list_jobs(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-list-machines.c b/src/systemctl/systemctl-list-machines.c
new file mode 100644 (file)
index 0000000..424778c
--- /dev/null
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "sd-login.h"
+
+#include "bus-map-properties.h"
+#include "hostname-util.h"
+#include "locale-util.h"
+#include "memory-util.h"
+#include "sort-util.h"
+#include "systemctl-list-machines.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+const struct bus_properties_map machine_info_property_map[] = {
+        { "SystemState",        "s", NULL, offsetof(struct machine_info, state)          },
+        { "NJobs",              "u", NULL, offsetof(struct machine_info, n_jobs)         },
+        { "NFailedUnits",       "u", NULL, offsetof(struct machine_info, n_failed_units) },
+        { "ControlGroup",       "s", NULL, offsetof(struct machine_info, control_group)  },
+        { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp)      },
+        {}
+};
+
+void machine_info_clear(struct machine_info *info) {
+        assert(info);
+
+        free(info->name);
+        free(info->state);
+        free(info->control_group);
+        zero(*info);
+}
+
+static void free_machines_list(struct machine_info *machine_infos, int n) {
+        int i;
+
+        if (!machine_infos)
+                return;
+
+        for (i = 0; i < n; i++)
+                machine_info_clear(&machine_infos[i]);
+
+        free(machine_infos);
+}
+
+static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
+        int r;
+
+        r = CMP(b->is_host, a->is_host);
+        if (r != 0)
+                return r;
+
+        return strcasecmp(a->name, b->name);
+}
+
+static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
+        int r;
+
+        assert(mi);
+
+        if (!bus) {
+                r = sd_bus_open_system_machine(&container, mi->name);
+                if (r < 0)
+                        return r;
+
+                bus = container;
+        }
+
+        r = bus_map_all_properties(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        machine_info_property_map,
+                        BUS_MAP_STRDUP,
+                        NULL,
+                        NULL,
+                        mi);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static bool output_show_machine(const char *name, char **patterns) {
+        return strv_fnmatch_or_empty(patterns, name, FNM_NOESCAPE);
+}
+
+static int get_machine_list(
+                sd_bus *bus,
+                struct machine_info **_machine_infos,
+                char **patterns) {
+
+        struct machine_info *machine_infos = NULL;
+        _cleanup_strv_free_ char **m = NULL;
+        _cleanup_free_ char *hn = NULL;
+        size_t sz = 0;
+        char **i;
+        int c = 0, r;
+
+        hn = gethostname_malloc();
+        if (!hn)
+                return log_oom();
+
+        if (output_show_machine(hn, patterns)) {
+                if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
+                        return log_oom();
+
+                machine_infos[c].is_host = true;
+                machine_infos[c].name = TAKE_PTR(hn);
+
+                (void) get_machine_properties(bus, &machine_infos[c]);
+                c++;
+        }
+
+        r = sd_get_machine_names(&m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get machine list: %m");
+
+        STRV_FOREACH(i, m) {
+                _cleanup_free_ char *class = NULL;
+
+                if (!output_show_machine(*i, patterns))
+                        continue;
+
+                sd_machine_get_class(*i, &class);
+                if (!streq_ptr(class, "container"))
+                        continue;
+
+                if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
+                        free_machines_list(machine_infos, c);
+                        return log_oom();
+                }
+
+                machine_infos[c].is_host = false;
+                machine_infos[c].name = strdup(*i);
+                if (!machine_infos[c].name) {
+                        free_machines_list(machine_infos, c);
+                        return log_oom();
+                }
+
+                (void) get_machine_properties(NULL, &machine_infos[c]);
+                c++;
+        }
+
+        *_machine_infos = machine_infos;
+        return c;
+}
+
+static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        struct machine_info *m;
+        bool state_missing = false;
+        int r;
+
+        assert(machine_infos || n == 0);
+
+        table = table_new("", "name", "state", "failed", "jobs");
+        if (!table)
+                return log_oom();
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_plain) {
+                /* Hide the 'glyph' column when --plain is requested */
+                r = table_hide_column_from_display(table, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to hide column: %m");
+        }
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        for (m = machine_infos; m < machine_infos + n; m++) {
+                _cleanup_free_ char *mname = NULL;
+                const char *on_state = "", *on_failed = "";
+                bool circle = false;
+
+                if (streq_ptr(m->state, "degraded")) {
+                        on_state = ansi_highlight_red();
+                        circle = true;
+                } else if (!streq_ptr(m->state, "running")) {
+                        on_state = ansi_highlight_yellow();
+                        circle = true;
+                }
+
+                if (m->n_failed_units > 0)
+                        on_failed = ansi_highlight_red();
+                else
+                        on_failed =  "";
+
+                if (!m->state)
+                        state_missing = true;
+
+                if (m->is_host)
+                        mname = strjoin(strna(m->name), " (host)");
+
+                r = table_add_many(table,
+                                   TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
+                                   TABLE_SET_COLOR, on_state,
+                                   TABLE_STRING, m->is_host ? mname : strna(m->name),
+                                   TABLE_STRING, strna(m->state),
+                                   TABLE_SET_COLOR, on_state,
+                                   TABLE_UINT32, m->n_failed_units,
+                                   TABLE_SET_COLOR, on_failed,
+                                   TABLE_UINT32, m->n_jobs);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        r = output_table(table);
+        if (r < 0)
+                return r;
+
+        if (!arg_no_legend) {
+                printf("\n");
+                if (state_missing && geteuid() != 0)
+                        printf("Notice: some information only available to privileged users was not shown.\n");
+                printf("%u machines listed.\n", n);
+        }
+
+        return 0;
+}
+
+int list_machines(int argc, char *argv[], void *userdata) {
+        struct machine_info *machine_infos = NULL;
+        sd_bus *bus;
+        int r, rc;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        typesafe_qsort(machine_infos, r, compare_machine_info);
+        rc = output_machines_list(machine_infos, r);
+        free_machines_list(machine_infos, r);
+
+        return rc;
+}
diff --git a/src/systemctl/systemctl-list-machines.h b/src/systemctl/systemctl-list-machines.h
new file mode 100644 (file)
index 0000000..c20b0e9
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "bus-map-properties.h"
+#include "time-util.h"
+
+int list_machines(int argc, char *argv[], void *userdata);
+
+struct machine_info {
+        bool is_host;
+        char *name;
+        char *state;
+        char *control_group;
+        uint32_t n_failed_units;
+        uint32_t n_jobs;
+        usec_t timestamp;
+};
+
+void machine_info_clear(struct machine_info *info);
+
+extern const struct bus_properties_map machine_info_property_map[];
diff --git a/src/systemctl/systemctl-list-unit-files.c b/src/systemctl/systemctl-list-unit-files.c
new file mode 100644 (file)
index 0000000..508909a
--- /dev/null
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "sort-util.h"
+#include "systemctl-list-unit-files.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
+        const char *d1, *d2;
+
+        d1 = strrchr(a->path, '.');
+        d2 = strrchr(b->path, '.');
+
+        if (d1 && d2) {
+                int r;
+
+                r = strcasecmp(d1, d2);
+                if (r != 0)
+                        return r;
+        }
+
+        return strcasecmp(basename(a->path), basename(b->path));
+}
+
+static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
+        assert(u);
+
+        if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
+                return false;
+
+        if (!strv_isempty(arg_types)) {
+                const char *dot;
+
+                dot = strrchr(u->path, '.');
+                if (!dot)
+                        return false;
+
+                if (!strv_find(arg_types, dot+1))
+                        return false;
+        }
+
+        if (!strv_isempty(states) &&
+            !strv_find(states, unit_file_state_to_string(u->state)))
+                return false;
+
+        return true;
+}
+
+static int output_unit_file_list(const UnitFileList *units, unsigned c) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
+        int r;
+
+        table = table_new("unit file", "state", "vendor preset");
+        if (!table)
+                return log_oom();
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        for (const UnitFileList *u = units; u < units + c; u++) {
+                const char *on_underline = NULL, *on_unit_color = NULL, *id;
+                bool underline;
+
+                underline = u + 1 < units + c &&
+                        !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
+
+                if (underline)
+                        on_underline = ansi_underline();
+
+                if (IN_SET(u->state,
+                           UNIT_FILE_MASKED,
+                           UNIT_FILE_MASKED_RUNTIME,
+                           UNIT_FILE_DISABLED,
+                           UNIT_FILE_BAD))
+                        on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                else if (IN_SET(u->state,
+                                UNIT_FILE_ENABLED,
+                                UNIT_FILE_ALIAS))
+                        on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
+                else
+                        on_unit_color = on_underline;
+
+                id = basename(u->path);
+
+                r = table_add_many(table,
+                                   TABLE_STRING, id,
+                                   TABLE_SET_BOTH_COLORS, strempty(on_underline),
+                                   TABLE_STRING, unit_file_state_to_string(u->state),
+                                   TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (show_preset_for_state(u->state)) {
+                        const char *unit_preset_str, *on_preset_color;
+
+                        r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
+                        if (r < 0) {
+                                unit_preset_str = "n/a";
+                                on_preset_color = underline ? on_underline : ansi_normal();
+                        } else if (r == 0) {
+                                unit_preset_str = "disabled";
+                                on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                        } else {
+                                unit_preset_str = "enabled";
+                                on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
+                        }
+
+                        r = table_add_many(table,
+                                           TABLE_STRING, unit_preset_str,
+                                           TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
+                } else
+                        r = table_add_many(table,
+                                           TABLE_EMPTY,
+                                           TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        r = output_table(table);
+        if (r < 0)
+                return r;
+
+        if (!arg_no_legend)
+                printf("\n%u unit files listed.\n", c);
+
+        return 0;
+}
+
+int list_unit_files(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ UnitFileList *units = NULL;
+        UnitFileList *unit;
+        size_t size = 0;
+        unsigned c = 0;
+        const char *state;
+        char *path;
+        int r;
+        bool fallback = false;
+
+        if (install_client_side()) {
+                Hashmap *h;
+                UnitFileList *u;
+                unsigned n_units;
+
+                h = hashmap_new(&string_hash_ops);
+                if (!h)
+                        return log_oom();
+
+                r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
+                if (r < 0) {
+                        unit_file_list_free(h);
+                        return log_error_errno(r, "Failed to get unit file list: %m");
+                }
+
+                n_units = hashmap_size(h);
+
+                units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
+                if (!units) {
+                        unit_file_list_free(h);
+                        return log_oom();
+                }
+
+                HASHMAP_FOREACH(u, h) {
+                        if (!output_show_unit_file(u, NULL, NULL))
+                                continue;
+
+                        units[c++] = *u;
+                        free(u);
+                }
+
+                assert(c <= n_units);
+                hashmap_free(h);
+
+                r = 0;
+        } else {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus *bus;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, arg_states);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                if (arg_with_dependencies) {
+                        _cleanup_strv_free_ char **names_with_deps = NULL;
+
+                        r = append_unit_dependencies(bus, strv_skip(argv, 1), &names_with_deps);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to append unit dependencies: %m");
+
+                        r = sd_bus_message_append_strv(m, names_with_deps);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                } else {
+                        r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+                if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                        /* Fallback to legacy ListUnitFiles method */
+                        fallback = true;
+                        log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
+                        m = sd_bus_message_unref(m);
+                        sd_bus_error_free(&error);
+
+                        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
+                        if (r < 0)
+                                return bus_log_create_error(r);
+
+                        r = sd_bus_call(bus, m, 0, &error, &reply);
+                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
+
+                r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
+                if (r < 0)
+                        return bus_log_parse_error(r);
+
+                while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
+
+                        if (!GREEDY_REALLOC(units, size, c + 1))
+                                return log_oom();
+
+                        units[c] = (struct UnitFileList) {
+                                path,
+                                unit_file_state_from_string(state)
+                        };
+
+                        if (output_show_unit_file(&units[c],
+                            fallback ? arg_states : NULL,
+                            fallback ? strv_skip(argv, 1) : NULL))
+                                c++;
+
+                }
+                if (r < 0)
+                        return bus_log_parse_error(r);
+
+                r = sd_bus_message_exit_container(reply);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+        }
+
+        (void) pager_open(arg_pager_flags);
+
+        typesafe_qsort(units, c, compare_unit_file_list);
+        r = output_unit_file_list(units, c);
+        if (r < 0)
+                return r;
+
+        if (install_client_side())
+                for (unit = units; unit < units + c; unit++)
+                        free(unit->path);
+
+        if (c == 0)
+                return -ENOENT;
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-list-unit-files.h b/src/systemctl/systemctl-list-unit-files.h
new file mode 100644 (file)
index 0000000..12f8492
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int list_unit_files(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c
new file mode 100644 (file)
index 0000000..15d8e4b
--- /dev/null
@@ -0,0 +1,770 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "sd-login.h"
+
+#include "bus-error.h"
+#include "format-table.h"
+#include "locale-util.h"
+#include "set.h"
+#include "sort-util.h"
+#include "systemctl-list-units.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static void message_set_freep(Set **set) {
+        set_free_with_destructor(*set, sd_bus_message_unref);
+}
+
+static int get_unit_list_recursive(
+                sd_bus *bus,
+                char **patterns,
+                UnitInfo **ret_unit_infos,
+                Set **ret_replies,
+                char ***ret_machines) {
+
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        _cleanup_(message_set_freep) Set *replies;
+        sd_bus_message *reply;
+        int c, r;
+
+        assert(bus);
+        assert(ret_replies);
+        assert(ret_unit_infos);
+        assert(ret_machines);
+
+        replies = set_new(NULL);
+        if (!replies)
+                return log_oom();
+
+        c = get_unit_list(bus, NULL, patterns, &unit_infos, 0, &reply);
+        if (c < 0)
+                return c;
+
+        r = set_put(replies, reply);
+        if (r < 0) {
+                sd_bus_message_unref(reply);
+                return log_oom();
+        }
+
+        if (arg_recursive) {
+                _cleanup_strv_free_ char **machines = NULL;
+                char **i;
+
+                r = sd_get_machine_names(&machines);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get machine names: %m");
+
+                STRV_FOREACH(i, machines) {
+                        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
+                        int k;
+
+                        r = sd_bus_open_system_machine(&container, *i);
+                        if (r < 0) {
+                                log_warning_errno(r, "Failed to connect to container %s, ignoring: %m", *i);
+                                continue;
+                        }
+
+                        k = get_unit_list(container, *i, patterns, &unit_infos, c, &reply);
+                        if (k < 0)
+                                return k;
+
+                        c = k;
+
+                        r = set_put(replies, reply);
+                        if (r < 0) {
+                                sd_bus_message_unref(reply);
+                                return log_oom();
+                        }
+                }
+
+                *ret_machines = TAKE_PTR(machines);
+        } else
+                *ret_machines = NULL;
+
+        *ret_unit_infos = TAKE_PTR(unit_infos);
+        *ret_replies = TAKE_PTR(replies);
+
+        return c;
+}
+
+static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        int r;
+
+        table = table_new("", "unit", "load", "active", "sub", "job", "description");
+        if (!table)
+                return log_oom();
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_plain) {
+                /* Hide the 'glyph' column when --plain is requested */
+                r = table_hide_column_from_display(table, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to hide column: %m");
+        }
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        int job_count = 0;
+        for (const UnitInfo *u = unit_infos; unit_infos && u < unit_infos + c; u++) {
+                _cleanup_free_ char *j = NULL;
+                const char *on_underline = "", *on_loaded = "", *on_active = "";
+                const char *on_circle = "", *id;
+                bool circle = false, underline = false;
+
+                if (u + 1 < unit_infos + c &&
+                    !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
+                        on_underline = ansi_underline();
+                        underline = true;
+                }
+
+                if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
+                        on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
+                        circle = true;
+                        on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                } else if (streq(u->active_state, "failed") && !arg_plain) {
+                        on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                        circle = true;
+                        on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                } else {
+                        on_circle = on_underline;
+                        on_active = on_underline;
+                        on_loaded = on_underline;
+                }
+
+                if (u->machine) {
+                        j = strjoin(u->machine, ":", u->id);
+                        if (!j)
+                                return log_oom();
+
+                        id = j;
+                } else
+                        id = u->id;
+
+                r = table_add_many(table,
+                                   TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
+                                   TABLE_SET_BOTH_COLORS, on_circle,
+                                   TABLE_STRING, id,
+                                   TABLE_SET_BOTH_COLORS, on_active,
+                                   TABLE_STRING, u->load_state,
+                                   TABLE_SET_BOTH_COLORS, on_loaded,
+                                   TABLE_STRING, u->active_state,
+                                   TABLE_SET_BOTH_COLORS, on_active,
+                                   TABLE_STRING, u->sub_state,
+                                   TABLE_SET_BOTH_COLORS, on_active,
+                                   TABLE_STRING, u->job_id ? u->job_type: "",
+                                   TABLE_SET_BOTH_COLORS, u->job_id ? on_underline : "",
+                                   TABLE_STRING, u->description,
+                                   TABLE_SET_BOTH_COLORS, on_underline);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (u->job_id != 0)
+                        job_count++;
+        }
+
+        if (job_count == 0) {
+                /* There's no data in the JOB column, so let's hide it */
+                r = table_hide_column_from_display(table, 5);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to hide column: %m");
+        }
+
+        r = output_table(table);
+        if (r < 0)
+                return r;
+
+        if (!arg_no_legend) {
+                const char *on, *off;
+                size_t records = table_get_rows(table) - 1;
+
+                if (records > 0) {
+                        puts("\n"
+                             "LOAD   = Reflects whether the unit definition was properly loaded.\n"
+                             "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
+                             "SUB    = The low-level unit activation state, values depend on unit type.");
+                        puts(job_count ? "JOB    = Pending job for the unit.\n" : "");
+                        on = ansi_highlight();
+                        off = ansi_normal();
+                } else {
+                        on = ansi_highlight_red();
+                        off = ansi_normal();
+                }
+
+                if (arg_all || strv_contains(arg_states, "inactive"))
+                        printf("%s%zu loaded units listed.%s\n"
+                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
+                               on, records, off);
+                else if (!arg_states)
+                        printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
+                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
+                               on, records, off);
+                else
+                        printf("%zu loaded units listed.\n", records);
+        }
+
+        return 0;
+}
+
+int list_units(int argc, char *argv[], void *userdata) {
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        _cleanup_(message_set_freep) Set *replies = NULL;
+        _cleanup_strv_free_ char **machines = NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        if (arg_with_dependencies) {
+                _cleanup_strv_free_ char **names = NULL;
+
+                r = append_unit_dependencies(bus, strv_skip(argv, 1), &names);
+                if (r < 0)
+                        return r;
+
+                r = get_unit_list_recursive(bus, names, &unit_infos, &replies, &machines);
+                if (r < 0)
+                        return r;
+        } else {
+                r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
+                if (r < 0)
+                        return r;
+        }
+
+        typesafe_qsort(unit_infos, r, unit_info_compare);
+        return output_units_list(unit_infos, r);
+}
+
+static int get_triggered_units(
+                sd_bus *bus,
+                const char* path,
+                char*** ret) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(ret);
+
+        r = sd_bus_get_property_strv(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Unit",
+                        "Triggers",
+                        &error,
+                        ret);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+static int get_listening(
+                sd_bus *bus,
+                const char* unit_path,
+                char*** listening) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        const char *type, *path;
+        int r, n = 0;
+
+        r = sd_bus_get_property(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        unit_path,
+                        "org.freedesktop.systemd1.Socket",
+                        "Listen",
+                        &error,
+                        &reply,
+                        "a(ss)");
+        if (r < 0)
+                return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
+
+                r = strv_extend(listening, type);
+                if (r < 0)
+                        return log_oom();
+
+                r = strv_extend(listening, path);
+                if (r < 0)
+                        return log_oom();
+
+                n++;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return n;
+}
+
+struct socket_info {
+        const char *machine;
+        const char* id;
+
+        char* type;
+        char* path;
+
+        /* Note: triggered is a list here, although it almost certainly will always be one
+         * unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */
+        char** triggered;
+
+        /* The strv above is shared. free is set only in the first one. */
+        bool own_triggered;
+};
+
+static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
+        int r;
+
+        assert(a);
+        assert(b);
+
+        r = strcasecmp_ptr(a->machine, b->machine);
+        if (r != 0)
+                return r;
+
+        r = strcmp(a->path, b->path);
+        if (r != 0)
+                return r;
+
+        return strcmp(a->type, b->type);
+}
+
+static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        struct socket_info *s;
+        const char *on, *off;
+        int r;
+
+        table = table_new("listen", "type", "unit", "activates");
+        if (!table)
+                return log_oom();
+
+        if (!arg_show_types) {
+                /* Hide the second (TYPE) column */
+                r = table_set_display(table, (size_t) 0, (size_t) 2, (size_t) 3, (size_t) -1);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set columns to display: %m");
+        }
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        if (cs) {
+                for (s = socket_infos; s < socket_infos + cs; s++) {
+                        _cleanup_free_ char *j = NULL;
+                        const char *path;
+
+                        if (s->machine) {
+                                j = strjoin(s->machine, ":", s->path);
+                                if (!j)
+                                        return log_oom();
+                                path = j;
+                        } else
+                                path = s->path;
+
+                        r = table_add_many(table,
+                                           TABLE_STRING, path,
+                                           TABLE_STRING, s->type,
+                                           TABLE_STRING, s->id);
+                        if (r < 0)
+                                return table_log_add_error(r);
+
+                        if (strv_isempty(s->triggered))
+                                r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
+                        else if (strv_length(s->triggered) == 1)
+                                r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]);
+                        else
+                                /* This should never happen, currently our socket units can only trigger a
+                                 * single unit. But let's handle this anyway, who knows what the future
+                                 * brings? */
+                                r = table_add_cell(table, NULL, TABLE_STRV, s->triggered);
+                        if (r < 0)
+                                return table_log_add_error(r);
+
+                }
+
+                on = ansi_highlight();
+                off = ansi_normal();
+        } else {
+                on = ansi_highlight_red();
+                off = ansi_normal();
+        }
+
+        r = output_table(table);
+        if (r < 0)
+                return r;
+
+        if (!arg_no_legend) {
+                printf("\n%s%u sockets listed.%s\n", on, cs, off);
+                if (!arg_all)
+                        printf("Pass --all to see loaded but inactive sockets, too.\n");
+        }
+
+        return 0;
+}
+
+int list_sockets(int argc, char *argv[], void *userdata) {
+        _cleanup_(message_set_freep) Set *replies = NULL;
+        _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **sockets_with_suffix = NULL;
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        _cleanup_free_ struct socket_info *socket_infos = NULL;
+        const UnitInfo *u;
+        struct socket_info *s;
+        unsigned cs = 0;
+        size_t size = 0;
+        int r, n;
+        sd_bus *bus;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix, NULL);
+        if (r < 0)
+                return r;
+
+        if (argc == 1 || sockets_with_suffix) {
+                n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
+
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
+                        int i, c;
+
+                        if (!endswith(u->id, ".socket"))
+                                continue;
+
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
+
+                        c = get_listening(bus, u->unit_path, &listening);
+                        if (c < 0) {
+                                r = c;
+                                goto cleanup;
+                        }
+
+                        if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
+
+                        for (i = 0; i < c; i++)
+                                socket_infos[cs + i] = (struct socket_info) {
+                                        .machine = u->machine,
+                                        .id = u->id,
+                                        .type = listening[i*2],
+                                        .path = listening[i*2 + 1],
+                                        .triggered = triggered,
+                                        .own_triggered = i==0,
+                                };
+
+                        /* from this point on we will cleanup those socket_infos */
+                        cs += c;
+                        free(listening);
+                        listening = triggered = NULL; /* avoid cleanup */
+                }
+
+                typesafe_qsort(socket_infos, cs, socket_info_compare);
+        }
+
+        output_sockets_list(socket_infos, cs);
+
+ cleanup:
+        assert(cs == 0 || socket_infos);
+        for (s = socket_infos; s < socket_infos + cs; s++) {
+                free(s->type);
+                free(s->path);
+                if (s->own_triggered)
+                        strv_free(s->triggered);
+        }
+
+        return r;
+}
+
+static int get_next_elapse(
+                sd_bus *bus,
+                const char *path,
+                dual_timestamp *next) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        dual_timestamp t;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(next);
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Timer",
+                        "NextElapseUSecMonotonic",
+                        &error,
+                        't',
+                        &t.monotonic);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Timer",
+                        "NextElapseUSecRealtime",
+                        &error,
+                        't',
+                        &t.realtime);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
+
+        *next = t;
+        return 0;
+}
+
+static int get_last_trigger(
+                sd_bus *bus,
+                const char *path,
+                usec_t *last) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(last);
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Timer",
+                        "LastTriggerUSec",
+                        &error,
+                        't',
+                        last);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+struct timer_info {
+        const char* machine;
+        const char* id;
+        usec_t next_elapse;
+        usec_t last_trigger;
+        char** triggered;
+};
+
+static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
+        int r;
+
+        assert(a);
+        assert(b);
+
+        r = strcasecmp_ptr(a->machine, b->machine);
+        if (r != 0)
+                return r;
+
+        r = CMP(a->next_elapse, b->next_elapse);
+        if (r != 0)
+                return r;
+
+        return strcmp(a->id, b->id);
+}
+
+static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        struct timer_info *t;
+        const char *on, *off;
+        int r;
+
+        assert(timer_infos || n == 0);
+
+        table = table_new("next", "left", "last", "passed", "unit", "activates");
+        if (!table)
+                return log_oom();
+
+        table_set_header(table, !arg_no_legend);
+        if (arg_full)
+                table_set_width(table, 0);
+
+        (void) table_set_empty_string(table, "-");
+
+        if (n > 0) {
+                for (t = timer_infos; t < timer_infos + n; t++) {
+                        _cleanup_free_ char *j = NULL, *activates = NULL;
+                        const char *unit;
+
+                        if (t->machine) {
+                                j = strjoin(t->machine, ":", t->id);
+                                if (!j)
+                                        return log_oom();
+                                unit = j;
+                        } else
+                                unit = t->id;
+
+                        activates = strv_join(t->triggered, ", ");
+                        if (!activates)
+                                return log_oom();
+
+                        r = table_add_many(table,
+                                           TABLE_TIMESTAMP, t->next_elapse,
+                                           TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
+                                           TABLE_TIMESTAMP, t->last_trigger,
+                                           TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
+                                           TABLE_STRING, unit,
+                                           TABLE_STRING, activates);
+                        if (r < 0)
+                                return table_log_add_error(r);
+                }
+
+                on = ansi_highlight();
+                off = ansi_normal();
+        } else {
+                on = ansi_highlight_red();
+                off = ansi_normal();
+        }
+
+        r = output_table(table);
+        if (r < 0)
+                return r;
+
+        if (!arg_no_legend) {
+                printf("\n%s%u timers listed.%s\n", on, n, off);
+                if (!arg_all)
+                        printf("Pass --all to see loaded but inactive timers, too.\n");
+        }
+
+        return 0;
+}
+
+usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
+        usec_t next_elapse;
+
+        assert(nw);
+        assert(next);
+
+        if (timestamp_is_set(next->monotonic)) {
+                usec_t converted;
+
+                if (next->monotonic > nw->monotonic)
+                        converted = nw->realtime + (next->monotonic - nw->monotonic);
+                else
+                        converted = nw->realtime - (nw->monotonic - next->monotonic);
+
+                if (timestamp_is_set(next->realtime))
+                        next_elapse = MIN(converted, next->realtime);
+                else
+                        next_elapse = converted;
+
+        } else
+                next_elapse = next->realtime;
+
+        return next_elapse;
+}
+
+int list_timers(int argc, char *argv[], void *userdata) {
+        _cleanup_(message_set_freep) Set *replies = NULL;
+        _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **timers_with_suffix = NULL;
+        _cleanup_free_ struct timer_info *timer_infos = NULL;
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        struct timer_info *t;
+        const UnitInfo *u;
+        size_t size = 0;
+        int n, c = 0;
+        dual_timestamp nw;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix, NULL);
+        if (r < 0)
+                return r;
+
+        if (argc == 1 || timers_with_suffix) {
+                n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
+
+                dual_timestamp_get(&nw);
+
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **triggered = NULL;
+                        dual_timestamp next = DUAL_TIMESTAMP_NULL;
+                        usec_t m, last = 0;
+
+                        if (!endswith(u->id, ".timer"))
+                                continue;
+
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
+
+                        r = get_next_elapse(bus, u->unit_path, &next);
+                        if (r < 0)
+                                goto cleanup;
+
+                        get_last_trigger(bus, u->unit_path, &last);
+
+                        if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
+
+                        m = calc_next_elapse(&nw, &next);
+
+                        timer_infos[c++] = (struct timer_info) {
+                                .machine = u->machine,
+                                .id = u->id,
+                                .next_elapse = m,
+                                .last_trigger = last,
+                                .triggered = TAKE_PTR(triggered),
+                        };
+                }
+
+                typesafe_qsort(timer_infos, c, timer_info_compare);
+        }
+
+        output_timers_list(timer_infos, c);
+
+ cleanup:
+        for (t = timer_infos; t < timer_infos + c; t++)
+                strv_free(t->triggered);
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-list-units.h b/src/systemctl/systemctl-list-units.h
new file mode 100644 (file)
index 0000000..a4c9775
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int list_units(int argc, char *argv[], void *userdata);
+int list_sockets(int argc, char *argv[], void *userdata);
+int list_timers(int argc, char *argv[], void *userdata);
+
+usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next);
diff --git a/src/systemctl/systemctl-log-setting.c b/src/systemctl/systemctl-log-setting.c
new file mode 100644 (file)
index 0000000..435ab0e
--- /dev/null
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "pretty-print.h"
+#include "syslog-util.h"
+#include "systemctl-log-setting.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static void give_log_control1_hint(const char *name) {
+        _cleanup_free_ char *link = NULL;
+
+        if (arg_quiet)
+                return;
+
+        (void) terminal_urlify_man("org.freedesktop.LogControl1", "5", &link);
+
+        log_notice("Hint: the service must declare BusName= and implement the appropriate D-Bus interface.\n"
+                   "      See the %s for details.", link ?: "org.freedesktop.LogControl1(5) man page");
+}
+
+static int log_setting_internal(sd_bus *bus, const BusLocator* bloc, const char *verb, const char *value) {
+        assert(bus);
+        assert(STR_IN_SET(verb, "log-level", "log-target", "service-log-level", "service-log-target"));
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool level = endswith(verb, "log-level");
+        int r;
+
+        if (value) {
+                if (level) {
+                        if (log_level_from_string(value) < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "\"%s\" is not a valid log level.", value);
+                }
+
+                r = bus_set_property(bus, bloc,
+                                     level ? "LogLevel" : "LogTarget",
+                                     &error, "s", value);
+                if (r >= 0)
+                        return 0;
+
+                log_error_errno(r, "Failed to set log %s of %s to %s: %s",
+                                level ? "level" : "target",
+                                bloc->destination, value, bus_error_message(&error, r));
+        } else {
+                _cleanup_free_ char *t = NULL;
+
+                r = bus_get_property_string(bus, bloc,
+                                            level ? "LogLevel" : "LogTarget",
+                                            &error, &t);
+                if (r >= 0) {
+                        puts(t);
+                        return 0;
+                }
+
+                log_error_errno(r, "Failed to get log %s of %s: %s",
+                                level ? "level" : "target",
+                                bloc->destination, bus_error_message(&error, r));
+        }
+
+        if (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
+                                           SD_BUS_ERROR_UNKNOWN_OBJECT,
+                                           SD_BUS_ERROR_UNKNOWN_INTERFACE,
+                                           SD_BUS_ERROR_UNKNOWN_PROPERTY))
+                give_log_control1_hint(bloc->destination);
+        return r;
+}
+
+int log_setting(int argc, char *argv[], void *userdata) {
+        sd_bus *bus;
+        int r;
+
+        assert(argc >= 1 && argc <= 2);
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        return log_setting_internal(bus, bus_systemd_mgr, argv[0], argv[1]);
+}
+
+static int service_name_to_dbus(sd_bus *bus, const char *name, char **ret_dbus_name) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *bus_name = NULL;
+        int r;
+
+        /* First, look for the BusName= property */
+        _cleanup_free_ char *dbus_path = unit_dbus_path_from_name(name);
+        if (!dbus_path)
+                return log_oom();
+
+        r = sd_bus_get_property_string(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                dbus_path,
+                                "org.freedesktop.systemd1.Service",
+                                "BusName",
+                                &error,
+                                &bus_name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to obtain BusName= property of %s: %s",
+                                       name, bus_error_message(&error, r));
+
+        if (isempty(bus_name)) {
+                log_error("Unit %s doesn't declare BusName=.", name);
+                give_log_control1_hint(name);
+                return -ENOLINK;
+        }
+
+        *ret_dbus_name = TAKE_PTR(bus_name);
+        return 0;
+}
+
+int service_log_setting(int argc, char *argv[], void *userdata) {
+        sd_bus *bus;
+        _cleanup_free_ char *unit = NULL, *dbus_name = NULL;
+        int r;
+
+        assert(argc >= 2 && argc <= 3);
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = unit_name_mangle_with_suffix(argv[1], argv[0],
+                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                         ".service", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
+
+        r = service_name_to_dbus(bus, unit, &dbus_name);
+        if (r < 0)
+                return r;
+
+        const BusLocator bloc = {
+                .destination = dbus_name,
+                .path = "/org/freedesktop/LogControl1",
+                .interface = "org.freedesktop.LogControl1",
+        };
+
+        return log_setting_internal(bus, &bloc, argv[0], argv[2]);
+}
diff --git a/src/systemctl/systemctl-log-setting.h b/src/systemctl/systemctl-log-setting.h
new file mode 100644 (file)
index 0000000..7e134a1
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int log_setting(int argc, char *argv[], void *userdata);
+int service_log_setting(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
new file mode 100644 (file)
index 0000000..20486c9
--- /dev/null
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "sd-login.h"
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "process-util.h"
+#include "systemctl-logind.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "user-util.h"
+
+int logind_set_wall_message(void) {
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        _cleanup_free_ char *m = NULL;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        m = strv_join(arg_wall, " ");
+        if (!m)
+                return log_oom();
+
+        log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
+        if (arg_dry_run)
+                return 0;
+
+        r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
+#endif
+        return 0;
+}
+
+/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
+int logind_reboot(enum action a) {
+#if ENABLE_LOGIND
+        static const struct {
+                const char *method;
+                const char *description;
+        } actions[_ACTION_MAX] = {
+                [ACTION_POWEROFF]               = { "PowerOff",             "power off system"                },
+                [ACTION_REBOOT]                 = { "Reboot",               "reboot system"                   },
+                [ACTION_HALT]                   = { "Halt",                 "halt system"                     },
+                [ACTION_SUSPEND]                = { "Suspend",              "suspend system"                  },
+                [ACTION_HIBERNATE]              = { "Hibernate",            "hibernate system"                },
+                [ACTION_HYBRID_SLEEP]           = { "HybridSleep",          "put system into hybrid sleep"    },
+                [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
+        };
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
+                return -EINVAL;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+        (void) logind_set_wall_message();
+
+        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
+
+        if (arg_dry_run)
+                return 0;
+
+        r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
+        if (r < 0)
+                return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
+
+        return 0;
+#else
+        return -ENOSYS;
+#endif
+}
+
+int logind_check_inhibitors(enum action a) {
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_strv_free_ char **sessions = NULL;
+        const char *what, *who, *why, *mode;
+        uint32_t uid, pid;
+        sd_bus *bus;
+        unsigned c = 0;
+        char **s;
+        int r;
+
+        if (arg_ignore_inhibitors || arg_force > 0)
+                return 0;
+
+        if (arg_when > 0)
+                return 0;
+
+        if (geteuid() == 0)
+                return 0;
+
+        if (!on_tty())
+                return 0;
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return 0;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
+        if (r < 0)
+                /* If logind is not around, then there are no inhibitors... */
+                return 0;
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
+                _cleanup_free_ char *comm = NULL, *user = NULL;
+                _cleanup_strv_free_ char **sv = NULL;
+
+                if (!streq(mode, "block"))
+                        continue;
+
+                sv = strv_split(what, ":");
+                if (!sv)
+                        return log_oom();
+
+                if (!pid_is_valid((pid_t) pid))
+                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
+
+                if (!strv_contains(sv,
+                                   IN_SET(a,
+                                          ACTION_HALT,
+                                          ACTION_POWEROFF,
+                                          ACTION_REBOOT,
+                                          ACTION_KEXEC) ? "shutdown" : "sleep"))
+                        continue;
+
+                get_process_comm(pid, &comm);
+                user = uid_to_name(uid);
+
+                log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
+                            who, (pid_t) pid, strna(comm), strna(user), why);
+
+                c++;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        /* Check for current sessions */
+        sd_get_sessions(&sessions);
+        STRV_FOREACH(s, sessions) {
+                _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
+
+                if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
+                        continue;
+
+                if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
+                        continue;
+
+                if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
+                        continue;
+
+                sd_session_get_tty(*s, &tty);
+                sd_session_get_seat(*s, &seat);
+                sd_session_get_service(*s, &service);
+                user = uid_to_name(uid);
+
+                log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
+                c++;
+        }
+
+        if (c <= 0)
+                return 0;
+
+        return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                               "Please retry operation after closing inhibitors and logging out other users.\n"
+                               "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
+                               action_table[a].verb);
+#else
+        return 0;
+#endif
+}
+
+int prepare_firmware_setup(void) {
+
+        if (!arg_firmware_setup)
+                return 0;
+
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
+        if (r < 0)
+                return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into firmware setup not supported.");
+#endif
+}
+
+int prepare_boot_loader_menu(void) {
+
+        if (arg_boot_loader_menu == USEC_INFINITY)
+                return 0;
+
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
+        if (r < 0)
+                return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into boot loader menu not supported.");
+#endif
+}
+
+int prepare_boot_loader_entry(void) {
+
+        if (!arg_boot_loader_entry)
+                return 0;
+
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
+        if (r < 0)
+                return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into boot loader entry not supported.");
+#endif
+}
+
+int logind_schedule_shutdown(void) {
+
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        char date[FORMAT_TIMESTAMP_MAX];
+        const char *action;
+        const char *log_action;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        switch (arg_action) {
+        case ACTION_HALT:
+                action = "halt";
+                log_action = "Shutdown";
+                break;
+        case ACTION_POWEROFF:
+                action = "poweroff";
+                log_action = "Shutdown";
+                break;
+        case ACTION_KEXEC:
+                action = "kexec";
+                log_action = "Reboot via kexec";
+                break;
+        case ACTION_EXIT:
+                action = "exit";
+                log_action = "Shutdown";
+                break;
+        case ACTION_REBOOT:
+        default:
+                action = "reboot";
+                log_action = "Reboot";
+                break;
+        }
+
+        if (arg_dry_run)
+                action = strjoina("dry-", action);
+
+        (void) logind_set_wall_message();
+
+        r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
+
+        if (!arg_quiet)
+                log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
+#endif
+}
+
+int logind_cancel_shutdown(void) {
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        (void) logind_set_wall_message();
+
+        r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Not compiled with logind support, cannot cancel scheduled shutdowns.");
+#endif
+}
+
+int help_boot_loader_entry(void) {
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_strv_free_ char **l = NULL;
+        sd_bus *bus;
+        char **i;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
+        if (r < 0)
+                return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
+
+        if (strv_isempty(l))
+                return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
+
+        STRV_FOREACH(i, l)
+                puts(*i);
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Not compiled with logind support, cannot display boot loader entries.");
+#endif
+}
diff --git a/src/systemctl/systemctl-logind.h b/src/systemctl/systemctl-logind.h
new file mode 100644 (file)
index 0000000..a9399e6
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "systemctl.h"
+
+int logind_set_wall_message(void);
+
+int logind_reboot(enum action a);
+int logind_check_inhibitors(enum action a);
+
+int prepare_firmware_setup(void);
+int prepare_boot_loader_menu(void);
+int prepare_boot_loader_entry(void);
+
+int logind_schedule_shutdown(void);
+int logind_cancel_shutdown(void);
+
+int help_boot_loader_entry(void);
diff --git a/src/systemctl/systemctl-preset-all.c b/src/systemctl/systemctl-preset-all.c
new file mode 100644 (file)
index 0000000..2fada83
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-preset-all.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int preset_all(int argc, char *argv[], void *userdata) {
+        UnitFileChange *changes = NULL;
+        size_t n_changes = 0;
+        int r;
+
+        if (install_client_side()) {
+                r = unit_file_preset_all(arg_scope, unit_file_flags_from_args(), arg_root, arg_preset_mode, &changes, &n_changes);
+                unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
+
+                if (r > 0)
+                        r = 0;
+        } else {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                sd_bus *bus;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                polkit_agent_open_maybe();
+
+                r = bus_call_method(
+                                bus,
+                                bus_systemd_mgr,
+                                "PresetAllUnitFiles",
+                                &error,
+                                &reply,
+                                "sbb",
+                                unit_file_preset_mode_to_string(arg_preset_mode),
+                                arg_runtime,
+                                arg_force);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
+
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
+                if (r < 0)
+                        goto finish;
+
+                if (arg_no_reload) {
+                        r = 0;
+                        goto finish;
+                }
+
+                r = daemon_reload(argc, argv, userdata);
+        }
+
+finish:
+        unit_file_changes_free(changes, n_changes);
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-preset-all.h b/src/systemctl/systemctl-preset-all.h
new file mode 100644 (file)
index 0000000..408e43b
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int preset_all(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-reset-failed.c b/src/systemctl/systemctl-reset-failed.c
new file mode 100644 (file)
index 0000000..bf7e26d
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-reset-failed.h"
+#include "systemctl-trivial-method.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int reset_failed(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **names = NULL;
+        sd_bus *bus;
+        char **name;
+        int r, q;
+
+        if (argc <= 1) /* Shortcut to trivial_method() if no argument is given */
+                return trivial_method(argc, argv, userdata);
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to expand names: %m");
+
+        STRV_FOREACH(name, names) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                q = bus_call_method(bus, bus_systemd_mgr, "ResetFailedUnit", &error, NULL, "s", *name);
+                if (q < 0) {
+                        log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
+                        if (r == 0)
+                                r = q;
+                }
+        }
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-reset-failed.h b/src/systemctl/systemctl-reset-failed.h
new file mode 100644 (file)
index 0000000..b7902ce
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int reset_failed(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-service-watchdogs.c b/src/systemctl/systemctl-service-watchdogs.c
new file mode 100644 (file)
index 0000000..6a954bf
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "parse-util.h"
+#include "systemctl-service-watchdogs.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int service_watchdogs(int argc, char *argv[], void *userdata) {
+        sd_bus *bus;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int b, r;
+
+        assert(argv);
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        if (argc == 1) {
+                /* get ServiceWatchdogs */
+                r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
+
+                printf("%s\n", yes_no(!!b));
+
+        } else {
+                /* set ServiceWatchdogs */
+                assert(argc == 2);
+
+                b = parse_boolean(argv[1]);
+                if (b < 0)
+                        return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
+
+                r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
+        }
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-service-watchdogs.h b/src/systemctl/systemctl-service-watchdogs.h
new file mode 100644 (file)
index 0000000..8189376
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int service_watchdogs(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-set-default.c b/src/systemctl/systemctl-set-default.c
new file mode 100644 (file)
index 0000000..423d881
--- /dev/null
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "proc-cmdline.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-set-default.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
+        char **ret = data;
+
+        if (streq(key, "systemd.unit")) {
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+                if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
+                        log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
+                        return 0;
+                }
+
+                return free_and_strdup_warn(ret, key);
+
+        } else if (!value) {
+                if (runlevel_to_target(key))
+                        return free_and_strdup_warn(ret, key);
+        }
+
+        return 0;
+}
+
+static void emit_cmdline_warning(void) {
+        if (arg_quiet || arg_root)
+                /* don't bother checking the commandline if we're operating on a container */
+                return;
+
+        _cleanup_free_ char *override = NULL;
+        int r;
+
+        r = proc_cmdline_parse(parse_proc_cmdline_item, &override, 0);
+        if (r < 0)
+                log_debug_errno(r, "Failed to parse kernel command line, ignoring: %m");
+        if (override)
+                log_notice("Note: found \"%s\" on the kernel commandline, which overrides the default unit.",
+                           override);
+}
+
+static int determine_default(char **ret_name) {
+        int r;
+
+        if (install_client_side()) {
+                r = unit_file_get_default(arg_scope, arg_root, ret_name);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get default target: %m");
+                return 0;
+
+        } else {
+                sd_bus *bus;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                const char *name;
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                r = bus_call_method(bus, bus_systemd_mgr, "GetDefaultTarget", &error, &reply, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
+
+                r = sd_bus_message_read(reply, "s", &name);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+
+                return free_and_strdup_warn(ret_name, name);
+        }
+}
+
+int get_default(int argc, char *argv[], void *userdata) {
+        _cleanup_free_ char *name = NULL;
+        int r;
+
+        r = determine_default(&name);
+        if (r < 0)
+                return r;
+
+        printf("%s\n", name);
+
+        emit_cmdline_warning();
+
+        return 0;
+}
+
+int set_default(int argc, char *argv[], void *userdata) {
+        _cleanup_free_ char *unit = NULL;
+        UnitFileChange *changes = NULL;
+        size_t n_changes = 0;
+        int r;
+
+        assert(argc >= 2);
+        assert(argv);
+
+        r = unit_name_mangle_with_suffix(argv[1], "set-default",
+                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                         ".target", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
+
+        if (install_client_side()) {
+                r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes);
+                unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
+
+                if (r > 0)
+                        r = 0;
+        } else {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                sd_bus *bus;
+
+                polkit_agent_open_maybe();
+
+                r = acquire_bus(BUS_MANAGER, &bus);
+                if (r < 0)
+                        return r;
+
+                r = bus_call_method(bus, bus_systemd_mgr, "SetDefaultTarget", &error, &reply, "sb", unit, 1);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
+
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
+                if (r < 0)
+                        goto finish;
+
+                /* Try to reload if enabled */
+                if (!arg_no_reload)
+                        r = daemon_reload(argc, argv, userdata);
+                else
+                        r = 0;
+        }
+
+        emit_cmdline_warning();
+
+        if (!arg_quiet) {
+                _cleanup_free_ char *final = NULL;
+
+                r = determine_default(&final);
+                if (r < 0)
+                        return r;
+
+                if (!streq(final, unit))
+                        log_notice("Note: \"%s\" is the default unit (possibly a runtime override).", final);
+        }
+
+finish:
+        unit_file_changes_free(changes, n_changes);
+
+        return r;
+}
diff --git a/src/systemctl/systemctl-set-default.h b/src/systemctl/systemctl-set-default.h
new file mode 100644 (file)
index 0000000..2067c8c
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int get_default(int argc, char *argv[], void *userdata);
+int set_default(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-set-environment.c b/src/systemctl/systemctl-set-environment.c
new file mode 100644 (file)
index 0000000..4d17c91
--- /dev/null
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "env-util.h"
+#include "escape.h"
+#include "systemctl-set-environment.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int print_variable(const char *s) {
+        const char *sep;
+        _cleanup_free_ char *esc = NULL;
+
+        sep = strchr(s, '=');
+        if (!sep)
+                return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
+                                       "Invalid environment block");
+
+        esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
+        if (!esc)
+                return log_oom();
+
+        printf("%.*s=%s\n", (int)(sep-s), s, esc);
+        return 0;
+}
+
+int show_environment(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        const char *text;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
+        if (r < 0)
+                return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
+                r = print_variable(text);
+                if (r < 0)
+                        return r;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return 0;
+}
+
+static void invalid_callback(const char *p, void *userdata) {
+        _cleanup_free_ char *t = cescape(p);
+
+        log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t));
+}
+
+int set_environment(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        const char *method;
+        sd_bus *bus;
+        int r;
+
+        assert(argc > 1);
+        assert(argv);
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        method = streq(argv[0], "set-environment")
+                ? "SetEnvironment"
+                : "UnsetEnvironment";
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+int import_environment(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (argc < 2) {
+                _cleanup_strv_free_ char **copy = NULL;
+
+                copy = strv_copy(environ);
+                if (!copy)
+                        return log_oom();
+
+                strv_env_clean_with_callback(copy, invalid_callback, NULL);
+
+                r = sd_bus_message_append_strv(m, copy);
+
+        } else {
+                char **a, **b;
+
+                r = sd_bus_message_open_container(m, 'a', "s");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                STRV_FOREACH(a, strv_skip(argv, 1)) {
+
+                        if (!env_name_is_valid(*a))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid environment variable name: %s", *a);
+
+                        STRV_FOREACH(b, environ) {
+                                const char *eq;
+
+                                eq = startswith(*b, *a);
+                                if (eq && *eq == '=') {
+
+                                        r = sd_bus_message_append(m, "s", *b);
+                                        if (r < 0)
+                                                return bus_log_create_error(r);
+
+                                        break;
+                                }
+                        }
+                }
+
+                r = sd_bus_message_close_container(m);
+        }
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-set-environment.h b/src/systemctl/systemctl-set-environment.h
new file mode 100644 (file)
index 0000000..57e51d4
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int show_environment(int argc, char *argv[], void *userdata);
+int set_environment(int argc, char *argv[], void *userdata);
+int import_environment(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-set-property.c b/src/systemctl/systemctl-set-property.c
new file mode 100644 (file)
index 0000000..891b67e
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-set-property.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int set_property(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *n = NULL;
+        UnitType t;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetUnitProperties");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
+
+        t = unit_name_to_type(n);
+        if (t < 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit type: %s", n);
+
+        r = sd_bus_message_append(m, "sb", n, arg_runtime);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-set-property.h b/src/systemctl/systemctl-set-property.h
new file mode 100644 (file)
index 0000000..e431de5
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int set_property(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c
new file mode 100644 (file)
index 0000000..119825f
--- /dev/null
@@ -0,0 +1,2135 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/mount.h>
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-map-properties.h"
+#include "bus-print-properties.h"
+#include "bus-unit-procs.h"
+#include "cgroup-show.h"
+#include "cpu-set-util.h"
+#include "errno-util.h"
+#include "exec-util.h"
+#include "exit-status.h"
+#include "format-util.h"
+#include "hexdecoct.h"
+#include "hostname-util.h"
+#include "in-addr-util.h"
+#include "journal-util.h"
+#include "list.h"
+#include "locale-util.h"
+#include "memory-util.h"
+#include "numa-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "sort-util.h"
+#include "string-table.h"
+#include "systemctl-list-machines.h"
+#include "systemctl-list-units.h"
+#include "systemctl-show.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "utf8.h"
+
+static OutputFlags get_output_flags(void) {
+        return
+                arg_all * OUTPUT_SHOW_ALL |
+                (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
+                colors_enabled() * OUTPUT_COLOR |
+                !arg_quiet * OUTPUT_WARN_CUTOFF;
+}
+
+typedef struct ExecStatusInfo {
+        char *name;
+
+        char *path;
+        char **argv;
+
+        bool ignore;
+
+        usec_t start_timestamp;
+        usec_t exit_timestamp;
+        pid_t pid;
+        int code;
+        int status;
+
+        ExecCommandFlags flags;
+
+        LIST_FIELDS(struct ExecStatusInfo, exec);
+} ExecStatusInfo;
+
+static void exec_status_info_free(ExecStatusInfo *i) {
+        assert(i);
+
+        free(i->name);
+        free(i->path);
+        strv_free(i->argv);
+        free(i);
+}
+
+static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i, bool is_ex_prop) {
+        _cleanup_strv_free_ char **ex_opts = NULL;
+        uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
+        const char *path;
+        uint32_t pid;
+        int32_t code, status;
+        int ignore, r;
+
+        assert(m);
+        assert(i);
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, is_ex_prop ? "sasasttttuii" : "sasbttttuii");
+        if (r < 0)
+                return bus_log_parse_error(r);
+        else if (r == 0)
+                return 0;
+
+        r = sd_bus_message_read(m, "s", &path);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        i->path = strdup(path);
+        if (!i->path)
+                return log_oom();
+
+        r = sd_bus_message_read_strv(m, &i->argv);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = is_ex_prop ? sd_bus_message_read_strv(m, &ex_opts) : sd_bus_message_read(m, "b", &ignore);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_read(m,
+                                "ttttuii",
+                                &start_timestamp, &start_timestamp_monotonic,
+                                &exit_timestamp, &exit_timestamp_monotonic,
+                                &pid,
+                                &code, &status);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        if (is_ex_prop) {
+                r = exec_command_flags_from_strv(ex_opts, &i->flags);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to convert strv to ExecCommandFlags: %m");
+
+                i->ignore = FLAGS_SET(i->flags, EXEC_COMMAND_IGNORE_FAILURE);
+        } else
+                i->ignore = ignore;
+
+        i->start_timestamp = (usec_t) start_timestamp;
+        i->exit_timestamp = (usec_t) exit_timestamp;
+        i->pid = (pid_t) pid;
+        i->code = code;
+        i->status = status;
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return 1;
+}
+
+typedef struct UnitCondition {
+        char *name;
+        char *param;
+        bool trigger;
+        bool negate;
+        int tristate;
+
+        LIST_FIELDS(struct UnitCondition, conditions);
+} UnitCondition;
+
+static void unit_condition_free(UnitCondition *c) {
+        if (!c)
+                return;
+
+        free(c->name);
+        free(c->param);
+        free(c);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
+
+typedef struct UnitStatusInfo {
+        const char *id;
+        const char *load_state;
+        const char *active_state;
+        const char *freezer_state;
+        const char *sub_state;
+        const char *unit_file_state;
+        const char *unit_file_preset;
+
+        const char *description;
+        const char *following;
+
+        char **documentation;
+
+        const char *fragment_path;
+        const char *source_path;
+        const char *control_group;
+
+        char **dropin_paths;
+
+        char **triggered_by;
+        char **triggers;
+
+        const char *load_error;
+        const char *result;
+
+        usec_t inactive_exit_timestamp;
+        usec_t inactive_exit_timestamp_monotonic;
+        usec_t active_enter_timestamp;
+        usec_t active_exit_timestamp;
+        usec_t inactive_enter_timestamp;
+
+        bool need_daemon_reload;
+        bool transient;
+
+        /* Service */
+        pid_t main_pid;
+        pid_t control_pid;
+        const char *status_text;
+        const char *pid_file;
+        bool running:1;
+        int status_errno;
+
+        usec_t start_timestamp;
+        usec_t exit_timestamp;
+
+        int exit_code, exit_status;
+
+        const char *log_namespace;
+
+        usec_t condition_timestamp;
+        bool condition_result;
+        LIST_HEAD(UnitCondition, conditions);
+
+        usec_t assert_timestamp;
+        bool assert_result;
+        bool failed_assert_trigger;
+        bool failed_assert_negate;
+        const char *failed_assert;
+        const char *failed_assert_parameter;
+        usec_t next_elapse_real;
+        usec_t next_elapse_monotonic;
+
+        /* Socket */
+        unsigned n_accepted;
+        unsigned n_connections;
+        unsigned n_refused;
+        bool accept;
+
+        /* Pairs of type, path */
+        char **listen;
+
+        /* Device */
+        const char *sysfs_path;
+
+        /* Mount, Automount */
+        const char *where;
+
+        /* Swap */
+        const char *what;
+
+        /* CGroup */
+        uint64_t memory_current;
+        uint64_t memory_min;
+        uint64_t memory_low;
+        uint64_t memory_high;
+        uint64_t memory_max;
+        uint64_t memory_swap_max;
+        uint64_t memory_limit;
+        uint64_t cpu_usage_nsec;
+        uint64_t tasks_current;
+        uint64_t tasks_max;
+        uint64_t ip_ingress_bytes;
+        uint64_t ip_egress_bytes;
+        uint64_t io_read_bytes;
+        uint64_t io_write_bytes;
+
+        uint64_t default_memory_min;
+        uint64_t default_memory_low;
+
+        LIST_HEAD(ExecStatusInfo, exec);
+} UnitStatusInfo;
+
+static void unit_status_info_free(UnitStatusInfo *info) {
+        ExecStatusInfo *p;
+        UnitCondition *c;
+
+        strv_free(info->documentation);
+        strv_free(info->dropin_paths);
+        strv_free(info->triggered_by);
+        strv_free(info->triggers);
+        strv_free(info->listen);
+
+        while ((c = info->conditions)) {
+                LIST_REMOVE(conditions, info->conditions, c);
+                unit_condition_free(c);
+        }
+
+        while ((p = info->exec)) {
+                LIST_REMOVE(exec, info->exec, p);
+                exec_status_info_free(p);
+        }
+}
+
+static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
+        if (streq_ptr(active_state, "failed")) {
+                *active_on = ansi_highlight_red();
+                *active_off = ansi_normal();
+        } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
+                *active_on = ansi_highlight_green();
+                *active_off = ansi_normal();
+        } else
+                *active_on = *active_off = "";
+}
+
+static void print_status_info(
+                sd_bus *bus,
+                UnitStatusInfo *i,
+                bool *ellipsized) {
+
+        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
+        const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
+        _cleanup_free_ char *formatted_path = NULL;
+        ExecStatusInfo *p;
+        usec_t timestamp;
+        const char *path;
+        char **t, **t2;
+        int r;
+
+        assert(i);
+
+        /* This shows pretty information about a unit. See print_property() for a low-level property
+         * printer */
+
+        format_active_state(i->active_state, &active_on, &active_off);
+
+        printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id));
+
+        if (i->description && !streq_ptr(i->id, i->description))
+                printf(" - %s", i->description);
+
+        printf("\n");
+
+        if (i->following)
+                printf("   Follow: unit currently follows state of %s\n", i->following);
+
+        if (STRPTR_IN_SET(i->load_state, "error", "not-found", "bad-setting")) {
+                on = ansi_highlight_red();
+                off = ansi_normal();
+        } else
+                on = off = "";
+
+        path = i->source_path ?: i->fragment_path;
+        if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
+                path = formatted_path;
+
+        if (!isempty(i->load_error))
+                printf("     Loaded: %s%s%s (Reason: %s)\n",
+                       on, strna(i->load_state), off, i->load_error);
+        else if (path && !isempty(i->unit_file_state)) {
+                bool show_preset = !isempty(i->unit_file_preset) &&
+                        show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
+
+                printf("     Loaded: %s%s%s (%s; %s%s%s)\n",
+                       on, strna(i->load_state), off,
+                       path,
+                       i->unit_file_state,
+                       show_preset ? "; vendor preset: " : "",
+                       show_preset ? i->unit_file_preset : "");
+
+        } else if (path)
+                printf("     Loaded: %s%s%s (%s)\n",
+                       on, strna(i->load_state), off, path);
+        else
+                printf("     Loaded: %s%s%s\n",
+                       on, strna(i->load_state), off);
+
+        if (i->transient)
+                printf("  Transient: yes\n");
+
+        if (!strv_isempty(i->dropin_paths)) {
+                _cleanup_free_ char *dir = NULL;
+                bool last = false;
+                char ** dropin;
+
+                STRV_FOREACH(dropin, i->dropin_paths) {
+                        _cleanup_free_ char *dropin_formatted = NULL;
+                        const char *df;
+
+                        if (!dir || last) {
+                                printf(dir ? "             " :
+                                             "    Drop-In: ");
+
+                                dir = mfree(dir);
+
+                                dir = dirname_malloc(*dropin);
+                                if (!dir) {
+                                        log_oom();
+                                        return;
+                                }
+
+                                printf("%s\n"
+                                       "             %s", dir,
+                                       special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
+                        }
+
+                        last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
+
+                        if (terminal_urlify_path(*dropin, basename(*dropin), &dropin_formatted) >= 0)
+                                df = dropin_formatted;
+                        else
+                                df = *dropin;
+
+                        printf("%s%s", df, last ? "\n" : ", ");
+                }
+        }
+
+        ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
+        if (ss)
+                printf("     Active: %s%s (%s)%s",
+                       active_on, strna(i->active_state), ss, active_off);
+        else
+                printf("     Active: %s%s%s",
+                       active_on, strna(i->active_state), active_off);
+
+        fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
+        if (fs)
+                printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
+
+        if (!isempty(i->result) && !streq(i->result, "success"))
+                printf(" (Result: %s)", i->result);
+
+        timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
+                    STRPTR_IN_SET(i->active_state, "inactive", "failed")  ? i->inactive_enter_timestamp :
+                    STRPTR_IN_SET(i->active_state, "activating")          ? i->inactive_exit_timestamp :
+                                                                            i->active_exit_timestamp;
+
+        s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
+        s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
+
+        if (s1)
+                printf(" since %s; %s\n", s2, s1);
+        else if (s2)
+                printf(" since %s\n", s2);
+        else
+                printf("\n");
+
+        STRV_FOREACH(t, i->triggered_by) {
+                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+                (void) get_state_one_unit(bus, *t, &state);
+                format_active_state(unit_active_state_to_string(state), &on, &off);
+
+                printf("%s %s%s%s %s\n",
+                       t == i->triggered_by ? "TriggeredBy:" : "            ",
+                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+                       *t);
+        }
+
+        if (endswith(i->id, ".timer")) {
+                char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
+                     tstamp2[FORMAT_TIMESTAMP_MAX];
+                const char *next_rel_time, *next_time;
+                dual_timestamp nw, next = {i->next_elapse_real,
+                                           i->next_elapse_monotonic};
+                usec_t next_elapse;
+
+                printf("    Trigger: ");
+
+                dual_timestamp_get(&nw);
+                next_elapse = calc_next_elapse(&nw, &next);
+                next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
+                next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
+
+                if (next_time && next_rel_time)
+                        printf("%s; %s\n", next_time, next_rel_time);
+                else
+                        printf("n/a\n");
+        }
+
+        STRV_FOREACH(t, i->triggers) {
+                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+                (void) get_state_one_unit(bus, *t, &state);
+                format_active_state(unit_active_state_to_string(state), &on, &off);
+
+                printf("%s %s%s%s %s\n",
+                       t == i->triggers ? "   Triggers:" : "            ",
+                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+                       *t);
+        }
+
+        if (!i->condition_result && i->condition_timestamp > 0) {
+                UnitCondition *c;
+                int n = 0;
+
+                s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
+                s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
+
+                printf("  Condition: start %scondition failed%s at %s%s%s\n",
+                       ansi_highlight_yellow(), ansi_normal(),
+                       s2, s1 ? "; " : "", strempty(s1));
+
+                LIST_FOREACH(conditions, c, i->conditions)
+                        if (c->tristate < 0)
+                                n++;
+
+                LIST_FOREACH(conditions, c, i->conditions)
+                        if (c->tristate < 0)
+                                printf("             %s %s=%s%s%s was not met\n",
+                                       --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
+                                       c->name,
+                                       c->trigger ? "|" : "",
+                                       c->negate ? "!" : "",
+                                       c->param);
+        }
+
+        if (!i->assert_result && i->assert_timestamp > 0) {
+                s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
+                s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
+
+                printf("     Assert: start %sassertion failed%s at %s%s%s\n",
+                       ansi_highlight_red(), ansi_normal(),
+                       s2, s1 ? "; " : "", strempty(s1));
+                if (i->failed_assert_trigger)
+                        printf("             none of the trigger assertions were met\n");
+                else if (i->failed_assert)
+                        printf("             %s=%s%s was not met\n",
+                               i->failed_assert,
+                               i->failed_assert_negate ? "!" : "",
+                               i->failed_assert_parameter);
+        }
+
+        if (i->sysfs_path)
+                printf("     Device: %s\n", i->sysfs_path);
+        if (i->where)
+                printf("      Where: %s\n", i->where);
+        if (i->what)
+                printf("       What: %s\n", i->what);
+
+        STRV_FOREACH(t, i->documentation) {
+                _cleanup_free_ char *formatted = NULL;
+                const char *q;
+
+                if (terminal_urlify(*t, NULL, &formatted) >= 0)
+                        q = formatted;
+                else
+                        q = *t;
+
+                printf("   %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
+        }
+
+        STRV_FOREACH_PAIR(t, t2, i->listen)
+                printf("   %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
+
+        if (i->accept) {
+                printf("   Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
+                if (i->n_refused)
+                        printf("   Refused: %u", i->n_refused);
+                printf("\n");
+        }
+
+        LIST_FOREACH(exec, p, i->exec) {
+                _cleanup_free_ char *argv = NULL;
+                bool good;
+
+                /* Only show exited processes here */
+                if (p->code == 0)
+                        continue;
+
+                /* Don't print ExecXYZEx= properties here since it will appear as a
+                 * duplicate of the non-Ex= variant. */
+                if (endswith(p->name, "Ex"))
+                        continue;
+
+                argv = strv_join(p->argv, " ");
+                printf("    Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
+
+                good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
+                if (!good) {
+                        on = ansi_highlight_red();
+                        off = ansi_normal();
+                } else
+                        on = off = "";
+
+                printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
+
+                if (p->code == CLD_EXITED) {
+                        const char *c;
+
+                        printf("status=%i", p->status);
+
+                        c = exit_status_to_string(p->status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
+                        if (c)
+                                printf("/%s", c);
+
+                } else
+                        printf("signal=%s", signal_to_string(p->status));
+
+                printf(")%s\n", off);
+
+                if (i->main_pid == p->pid &&
+                    i->start_timestamp == p->start_timestamp &&
+                    i->exit_timestamp == p->start_timestamp)
+                        /* Let's not show this twice */
+                        i->main_pid = 0;
+
+                if (p->pid == i->control_pid)
+                        i->control_pid = 0;
+        }
+
+        if (i->main_pid > 0 || i->control_pid > 0) {
+                if (i->main_pid > 0) {
+                        printf("   Main PID: "PID_FMT, i->main_pid);
+
+                        if (i->running) {
+
+                                if (arg_transport == BUS_TRANSPORT_LOCAL) {
+                                        _cleanup_free_ char *comm = NULL;
+
+                                        (void) get_process_comm(i->main_pid, &comm);
+                                        if (comm)
+                                                printf(" (%s)", comm);
+                                }
+
+                        } else if (i->exit_code > 0) {
+                                printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
+
+                                if (i->exit_code == CLD_EXITED) {
+                                        const char *c;
+
+                                        printf("status=%i", i->exit_status);
+
+                                        c = exit_status_to_string(i->exit_status,
+                                                                  EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
+                                        if (c)
+                                                printf("/%s", c);
+
+                                } else
+                                        printf("signal=%s", signal_to_string(i->exit_status));
+                                printf(")");
+                        }
+                }
+
+                if (i->control_pid > 0) {
+                        _cleanup_free_ char *c = NULL;
+
+                        if (i->main_pid > 0)
+                                fputs("; Control PID: ", stdout);
+                        else
+                                fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
+
+                        printf(PID_FMT, i->control_pid);
+
+                        if (arg_transport == BUS_TRANSPORT_LOCAL) {
+                                (void) get_process_comm(i->control_pid, &c);
+                                if (c)
+                                        printf(" (%s)", c);
+                        }
+                }
+
+                printf("\n");
+        }
+
+        if (i->status_text)
+                printf("     Status: \"%s\"\n", i->status_text);
+        if (i->status_errno > 0)
+                printf("      Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
+
+        if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
+                char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
+
+                printf("         IP: %s in, %s out\n",
+                        format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
+                        format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
+        }
+
+        if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
+                char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
+
+                printf("         IO: %s read, %s written\n",
+                        format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
+                        format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
+        }
+
+        if (i->tasks_current != (uint64_t) -1) {
+                printf("      Tasks: %" PRIu64, i->tasks_current);
+
+                if (i->tasks_max != (uint64_t) -1)
+                        printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
+                else
+                        printf("\n");
+        }
+
+        if (i->memory_current != (uint64_t) -1) {
+                char buf[FORMAT_BYTES_MAX];
+
+                printf("     Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
+
+                if (i->memory_min > 0 || i->memory_low > 0 ||
+                    i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
+                    i->memory_swap_max != CGROUP_LIMIT_MAX ||
+                    i->memory_limit != CGROUP_LIMIT_MAX) {
+                        const char *prefix = "";
+
+                        printf(" (");
+                        if (i->memory_min > 0) {
+                                printf("%smin: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_min));
+                                prefix = " ";
+                        }
+                        if (i->memory_low > 0) {
+                                printf("%slow: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_low));
+                                prefix = " ";
+                        }
+                        if (i->memory_high != CGROUP_LIMIT_MAX) {
+                                printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
+                                prefix = " ";
+                        }
+                        if (i->memory_max != CGROUP_LIMIT_MAX) {
+                                printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
+                                prefix = " ";
+                        }
+                        if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
+                                printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
+                                prefix = " ";
+                        }
+                        if (i->memory_limit != CGROUP_LIMIT_MAX) {
+                                printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
+                                prefix = " ";
+                        }
+                        printf(")");
+                }
+                printf("\n");
+        }
+
+        if (i->cpu_usage_nsec != (uint64_t) -1) {
+                char buf[FORMAT_TIMESPAN_MAX];
+                printf("        CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
+        }
+
+        if (i->control_group) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                static const char prefix[] = "             ";
+                unsigned c;
+
+                printf("     CGroup: %s\n", i->control_group);
+
+                c = columns();
+                if (c > sizeof(prefix) - 1)
+                        c -= sizeof(prefix) - 1;
+                else
+                        c = 0;
+
+                r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
+                if (r == -EBADR) {
+                        unsigned k = 0;
+                        pid_t extra[2];
+
+                        /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
+
+                        if (i->main_pid > 0)
+                                extra[k++] = i->main_pid;
+
+                        if (i->control_pid > 0)
+                                extra[k++] = i->control_pid;
+
+                        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
+                } else if (r < 0)
+                        log_warning_errno(r, "Failed to dump process list for '%s', ignoring: %s",
+                                          i->id, bus_error_message(&error, r));
+        }
+
+        if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
+                show_journal_by_unit(
+                                stdout,
+                                i->id,
+                                i->log_namespace,
+                                arg_output,
+                                0,
+                                i->inactive_exit_timestamp_monotonic,
+                                arg_lines,
+                                getuid(),
+                                get_output_flags() | OUTPUT_BEGIN_NEWLINE,
+                                SD_JOURNAL_LOCAL_ONLY,
+                                arg_scope == UNIT_FILE_SYSTEM,
+                                ellipsized);
+
+        if (i->need_daemon_reload)
+                warn_unit_file_changed(i->id);
+}
+
+static void show_unit_help(UnitStatusInfo *i) {
+        char **p;
+
+        assert(i);
+
+        if (!i->documentation) {
+                log_info("Documentation for %s not known.", i->id);
+                return;
+        }
+
+        STRV_FOREACH(p, i->documentation)
+                if (startswith(*p, "man:"))
+                        show_man_page(*p + 4, false);
+                else
+                        log_info("Can't show: %s", *p);
+}
+
+static int map_main_pid(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        UnitStatusInfo *i = userdata;
+        uint32_t u;
+        int r;
+
+        r = sd_bus_message_read(m, "u", &u);
+        if (r < 0)
+                return r;
+
+        i->main_pid = (pid_t) u;
+        i->running = u > 0;
+
+        return 0;
+}
+
+static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        const char *message, **p = userdata;
+        int r;
+
+        r = sd_bus_message_read(m, "(ss)", NULL, &message);
+        if (r < 0)
+                return r;
+
+        if (!isempty(message))
+                *p = message;
+
+        return 0;
+}
+
+static int map_listen(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        const char *type, *path;
+        char ***p = userdata;
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+        if (r < 0)
+                return r;
+
+        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
+
+                r = strv_extend(p, type);
+                if (r < 0)
+                        return r;
+
+                r = strv_extend(p, path);
+                if (r < 0)
+                        return r;
+        }
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        UnitStatusInfo *i = userdata;
+        const char *cond, *param;
+        int trigger, negate;
+        int32_t state;
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
+        if (r < 0)
+                return r;
+
+        while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
+                _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
+
+                c = new(UnitCondition, 1);
+                if (!c)
+                        return -ENOMEM;
+
+                *c = (UnitCondition) {
+                        .name = strdup(cond),
+                        .param = strdup(param),
+                        .trigger = trigger,
+                        .negate = negate,
+                        .tristate = state,
+                };
+
+                if (!c->name || !c->param)
+                        return -ENOMEM;
+
+                LIST_PREPEND(conditions, i->conditions, TAKE_PTR(c));
+        }
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int map_asserts(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        UnitStatusInfo *i = userdata;
+        const char *cond, *param;
+        int trigger, negate;
+        int32_t state;
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
+        if (r < 0)
+                return r;
+
+        while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
+                if (state < 0 && (!trigger || !i->failed_assert)) {
+                        i->failed_assert = cond;
+                        i->failed_assert_trigger = trigger;
+                        i->failed_assert_negate = negate;
+                        i->failed_assert_parameter = param;
+                }
+        }
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        _cleanup_free_ ExecStatusInfo *info = NULL;
+        ExecStatusInfo *last;
+        UnitStatusInfo *i = userdata;
+        bool is_ex_prop = endswith(member, "Ex");
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
+        if (r < 0)
+                return r;
+
+        info = new0(ExecStatusInfo, 1);
+        if (!info)
+                return -ENOMEM;
+
+        LIST_FIND_TAIL(exec, i->exec, last);
+
+        while ((r = exec_status_info_deserialize(m, info, is_ex_prop)) > 0) {
+
+                info->name = strdup(member);
+                if (!info->name)
+                        return -ENOMEM;
+
+                LIST_INSERT_AFTER(exec, i->exec, last, info);
+                last = info;
+
+                info = new0(ExecStatusInfo, 1);
+                if (!info)
+                        return -ENOMEM;
+        }
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
+        char bus_type;
+        const char *contents;
+        int r;
+
+        assert(name);
+        assert(m);
+
+        /* This is a low-level property printer, see print_status_info() for the nicer output */
+
+        r = sd_bus_message_peek_type(m, &bus_type, &contents);
+        if (r < 0)
+                return r;
+
+        switch (bus_type) {
+
+        case SD_BUS_TYPE_INT32:
+                if (endswith(name, "ActionExitStatus")) {
+                        int32_t i;
+
+                        r = sd_bus_message_read_basic(m, bus_type, &i);
+                        if (r < 0)
+                                return r;
+
+                        if (i >= 0 && i <= 255)
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "[not set]");
+
+                        return 1;
+                } else if (streq(name, "NUMAPolicy")) {
+                        int32_t i;
+
+                        r = sd_bus_message_read_basic(m, bus_type, &i);
+                        if (r < 0)
+                                return r;
+
+                        bus_print_property_valuef(name, expected_value, value, "%s", strna(mpol_to_string(i)));
+
+                        return 1;
+                }
+                break;
+
+        case SD_BUS_TYPE_STRUCT:
+
+                if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
+                        uint32_t u;
+
+                        r = sd_bus_message_read(m, "(uo)", &u, NULL);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (u > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "");
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
+                        const char *s;
+
+                        r = sd_bus_message_read(m, "(so)", &s, NULL);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(s))
+                                bus_print_property_value(name, expected_value, value, s);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
+                        const char *a = NULL, *b = NULL;
+
+                        r = sd_bus_message_read(m, "(ss)", &a, &b);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (!isempty(a) || !isempty(b))
+                                bus_print_property_valuef(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "");
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies")) {
+                        _cleanup_strv_free_ char **l = NULL;
+                        int allow_list;
+
+                        r = sd_bus_message_enter_container(m, 'r', "bas");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read(m, "b", &allow_list);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_strv(m, &l);
+                        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 (all || allow_list || !strv_isempty(l)) {
+                                bool first = true;
+                                char **i;
+
+                                if (!value) {
+                                        fputs(name, stdout);
+                                        fputc('=', stdout);
+                                }
+
+                                if (!allow_list)
+                                        fputc('~', stdout);
+
+                                STRV_FOREACH(i, l) {
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        fputs(*i, stdout);
+                                }
+                                fputc('\n', stdout);
+                        }
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
+                        int ignore;
+                        const char *s;
+
+                        r = sd_bus_message_read(m, "(bs)", &ignore, &s);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (!isempty(s))
+                                bus_print_property_valuef(name, expected_value, value, "%s%s", ignore ? "-" : "", s);
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "");
+
+                        return 1;
+
+                } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
+                        const int32_t *status, *signal;
+                        size_t n_status, n_signal, i;
+
+                        r = sd_bus_message_enter_container(m, 'r', "aiai");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_array(m, 'i', (const void **) &status, &n_status);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_array(m, 'i', (const void **) &signal, &n_signal);
+                        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);
+
+                        n_status /= sizeof(int32_t);
+                        n_signal /= sizeof(int32_t);
+
+                        if (all || n_status > 0 || n_signal > 0) {
+                                bool first = true;
+
+                                if (!value) {
+                                        fputs(name, stdout);
+                                        fputc('=', stdout);
+                                }
+
+                                for (i = 0; i < n_status; i++) {
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        printf("%"PRIi32, status[i]);
+                                }
+
+                                for (i = 0; i < n_signal; i++) {
+                                        const char *str;
+
+                                        str = signal_to_string((int) signal[i]);
+
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        if (str)
+                                                fputs(str, stdout);
+                                        else
+                                                printf("%"PRIi32, status[i]);
+                                }
+
+                                fputc('\n', stdout);
+                        }
+                        return 1;
+                }
+
+                break;
+
+        case SD_BUS_TYPE_ARRAY:
+
+                if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
+                        const char *path;
+                        int ignore;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
+
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
+                        const char *type, *path;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
+                        const char *type, *path;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
+                        const char *base;
+                        uint64_t v, next_elapse;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
+                                char timespan1[FORMAT_TIMESPAN_MAX] = "n/a", timespan2[FORMAT_TIMESPAN_MAX] = "n/a";
+
+                                (void) format_timespan(timespan1, sizeof timespan1, v, 0);
+                                (void) format_timespan(timespan2, sizeof timespan2, next_elapse, 0);
+
+                                bus_print_property_valuef(name, expected_value, value,
+                                                          "{ %s=%s ; next_elapse=%s }", base, timespan1, timespan2);
+                        }
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
+                        const char *base, *spec;
+                        uint64_t next_elapse;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
+                                char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
+
+                                (void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
+                                bus_print_property_valuef(name, expected_value, value,
+                                                          "{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
+                        }
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
+                        ExecStatusInfo info = {};
+                        bool is_ex_prop = endswith(name, "Ex");
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
+                                char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
+                                _cleanup_strv_free_ char **optv = NULL;
+                                _cleanup_free_ char *tt, *o = NULL;
+
+                                tt = strv_join(info.argv, " ");
+
+                                if (is_ex_prop) {
+                                        r = exec_command_flags_to_strv(info.flags, &optv);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
+
+                                        o = strv_join(optv, " ");
+
+                                        bus_print_property_valuef(name, expected_value, value,
+                                                                  "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+                                                                  strna(info.path),
+                                                                  strna(tt),
+                                                                  strna(o),
+                                                                  strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
+                                                                  strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
+                                                                  info.pid,
+                                                                  sigchld_code_to_string(info.code),
+                                                                  info.status,
+                                                                  info.code == CLD_EXITED ? "" : "/",
+                                                                  strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+                                } else
+                                        bus_print_property_valuef(name, expected_value, value,
+                                                                  "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+                                                                  strna(info.path),
+                                                                  strna(tt),
+                                                                  yes_no(info.ignore),
+                                                                  strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
+                                                                  strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
+                                                                  info.pid,
+                                                                  sigchld_code_to_string(info.code),
+                                                                  info.status,
+                                                                  info.code == CLD_EXITED ? "" : "/",
+                                                                  strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+
+                                free(info.path);
+                                strv_free(info.argv);
+                                zero(info);
+                        }
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
+                        const char *path, *rwm;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path), strna(rwm));
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
+                           STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
+                        const char *path;
+                        uint64_t weight;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
+                           (cgroup_io_limit_type_from_string(name) >= 0 ||
+                            STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
+                        const char *path;
+                        uint64_t bandwidth;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
+                        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);
+
+                        return 1;
+
+                }  else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
+                            streq(name, "IODeviceLatencyTargetUSec")) {
+                        char ts[FORMAT_TIMESPAN_MAX];
+                        const char *path;
+                        uint64_t target;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path),
+                                                          format_timespan(ts, sizeof(ts), target, 1));
+                        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);
+
+                        return 1;
+
+                } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "StandardInputData", "RootHashSignature")) {
+                        _cleanup_free_ char *h = NULL;
+                        const void *p;
+                        size_t sz;
+                        ssize_t n;
+
+                        r = sd_bus_message_read_array(m, 'y', &p, &sz);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        n = base64mem(p, sz, &h);
+                        if (n < 0)
+                                return log_oom();
+
+                        bus_print_property_value(name, expected_value, value, h);
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
+                        _cleanup_free_ char *addresses = NULL;
+
+                        r = sd_bus_message_enter_container(m, 'a', "(iayu)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        for (;;) {
+                                _cleanup_free_ char *str = NULL;
+                                uint32_t prefixlen;
+                                int32_t family;
+                                const void *ap;
+                                size_t an;
+
+                                r = sd_bus_message_enter_container(m, 'r', "iayu");
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+                                if (r == 0)
+                                        break;
+
+                                r = sd_bus_message_read(m, "i", &family);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                r = sd_bus_message_read_array(m, 'y', &ap, &an);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                r = sd_bus_message_read(m, "u", &prefixlen);
+                                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 (!IN_SET(family, AF_INET, AF_INET6))
+                                        continue;
+
+                                if (an != FAMILY_ADDRESS_SIZE(family))
+                                        continue;
+
+                                if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
+                                        continue;
+
+                                if (in_addr_prefix_to_string(family, (union in_addr_union *) ap, prefixlen, &str) < 0)
+                                        continue;
+
+                                if (!strextend_with_separator(&addresses, " ", str, NULL))
+                                        return log_oom();
+                        }
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(addresses))
+                                bus_print_property_value(name, expected_value, value, strempty(addresses));
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
+                        _cleanup_free_ char *paths = NULL;
+                        const char *source, *dest;
+                        int ignore_enoent;
+                        uint64_t rbind;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssbt)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ssbt)", &source, &dest, &ignore_enoent, &rbind)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+
+                                if (isempty(source))
+                                        continue;
+
+                                if (asprintf(&str, "%s%s%s%s%s",
+                                             ignore_enoent ? "-" : "",
+                                             source,
+                                             isempty(dest) ? "" : ":",
+                                             strempty(dest),
+                                             rbind == MS_REC ? ":rbind" : "") < 0)
+                                        return log_oom();
+
+                                if (!strextend_with_separator(&paths, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        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 (all || !isempty(paths))
+                                bus_print_property_value(name, expected_value, value, strempty(paths));
+
+                        return 1;
+
+                } else if (streq(name, "TemporaryFileSystem")) {
+                        _cleanup_free_ char *paths = NULL;
+                        const char *target, *option;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &target, &option)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+
+                                if (isempty(target))
+                                        continue;
+
+                                if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0)
+                                        return log_oom();
+
+                                if (!strextend_with_separator(&paths, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        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 (all || !isempty(paths))
+                                bus_print_property_value(name, expected_value, value, strempty(paths));
+
+                        return 1;
+
+                } else if (streq(name, "LogExtraFields")) {
+                        _cleanup_free_ char *fields = NULL;
+                        const void *p;
+                        size_t sz;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "ay");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read_array(m, 'y', &p, &sz)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+                                const char *eq;
+
+                                if (memchr(p, 0, sz))
+                                        continue;
+
+                                eq = memchr(p, '=', sz);
+                                if (!eq)
+                                        continue;
+
+                                if (!journal_field_valid(p, eq - (const char*) p, false))
+                                        continue;
+
+                                str = malloc(sz + 1);
+                                if (!str)
+                                        return log_oom();
+
+                                memcpy(str, p, sz);
+                                str[sz] = '\0';
+
+                                if (!utf8_is_valid(str))
+                                        continue;
+
+                                if (!strextend_with_separator(&fields, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        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 (all || !isempty(fields))
+                                bus_print_property_value(name, expected_value, value, strempty(fields));
+
+                        return 1;
+                } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes", "EffectiveCPUs", "EffectiveMemoryNodes")) {
+                        _cleanup_free_ char *affinity = NULL;
+                        _cleanup_(cpu_set_reset) CPUSet set = {};
+                        const void *a;
+                        size_t n;
+
+                        r = sd_bus_message_read_array(m, 'y', &a, &n);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = cpu_set_from_dbus(a, n, &set);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to deserialize %s: %m", name);
+
+                        affinity = cpu_set_to_range_string(&set);
+                        if (!affinity)
+                                return log_oom();
+
+                        bus_print_property_value(name, expected_value, value, affinity);
+
+                        return 1;
+                } else if (streq(name, "MountImages")) {
+                        _cleanup_free_ char *paths = NULL;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssba(ss))");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        for (;;) {
+                                _cleanup_free_ char *str = NULL;
+                                const char *source, *destination, *partition, *mount_options;
+                                int ignore_enoent;
+
+                                r = sd_bus_message_enter_container(m, 'r', "ssba(ss)");
+                                if (r < 0)
+                                        return r;
+
+                                r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
+                                if (r <= 0)
+                                        break;
+
+                                str = strjoin(ignore_enoent ? "-" : "",
+                                              source,
+                                              ":",
+                                              destination);
+                                if (!str)
+                                        return log_oom();
+
+                                r = sd_bus_message_enter_container(m, 'a', "(ss)");
+                                if (r < 0)
+                                        return r;
+
+                                while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0) {
+                                        _cleanup_free_ char *previous = NULL;
+
+                                        previous = TAKE_PTR(str);
+                                        str = strjoin(strempty(previous), previous ? ":" : "", partition, ":", mount_options);
+                                        if (!str)
+                                                return log_oom();
+                                }
+                                if (r < 0)
+                                        return r;
+
+                                if (!strextend_with_separator(&paths, " ", str, NULL))
+                                        return log_oom();
+
+                                r = sd_bus_message_exit_container(m);
+                                if (r < 0)
+                                        return r;
+
+                                r = sd_bus_message_exit_container(m);
+                                if (r < 0)
+                                        return r;
+                        }
+                        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 (all || !isempty(paths))
+                                bus_print_property_value(name, expected_value, value, strempty(paths));
+
+                        return 1;
+
+                }
+
+                break;
+        }
+
+        return 0;
+}
+
+typedef enum SystemctlShowMode{
+        SYSTEMCTL_SHOW_PROPERTIES,
+        SYSTEMCTL_SHOW_STATUS,
+        SYSTEMCTL_SHOW_HELP,
+        _SYSTEMCTL_SHOW_MODE_MAX,
+        _SYSTEMCTL_SHOW_MODE_INVALID = -1,
+} SystemctlShowMode;
+
+static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
+        [SYSTEMCTL_SHOW_PROPERTIES] = "show",
+        [SYSTEMCTL_SHOW_STATUS] = "status",
+        [SYSTEMCTL_SHOW_HELP] = "help",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
+
+static int show_one(
+                sd_bus *bus,
+                const char *path,
+                const char *unit,
+                SystemctlShowMode show_mode,
+                bool *new_line,
+                bool *ellipsized) {
+
+        static const struct bus_properties_map property_map[] = {
+                { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
+                { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
+                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
+                { "Documentation",                  "as",              NULL,           offsetof(UnitStatusInfo, documentation)                     },
+                {}
+        }, status_map[] = {
+                { "Id",                             "s",               NULL,           offsetof(UnitStatusInfo, id)                                },
+                { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
+                { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
+                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
+                { "SubState",                       "s",               NULL,           offsetof(UnitStatusInfo, sub_state)                         },
+                { "UnitFileState",                  "s",               NULL,           offsetof(UnitStatusInfo, unit_file_state)                   },
+                { "UnitFilePreset",                 "s",               NULL,           offsetof(UnitStatusInfo, unit_file_preset)                  },
+                { "Description",                    "s",               NULL,           offsetof(UnitStatusInfo, description)                       },
+                { "Following",                      "s",               NULL,           offsetof(UnitStatusInfo, following)                         },
+                { "Documentation",                  "as",              NULL,           offsetof(UnitStatusInfo, documentation)                     },
+                { "FragmentPath",                   "s",               NULL,           offsetof(UnitStatusInfo, fragment_path)                     },
+                { "SourcePath",                     "s",               NULL,           offsetof(UnitStatusInfo, source_path)                       },
+                { "ControlGroup",                   "s",               NULL,           offsetof(UnitStatusInfo, control_group)                     },
+                { "DropInPaths",                    "as",              NULL,           offsetof(UnitStatusInfo, dropin_paths)                      },
+                { "LoadError",                      "(ss)",            map_load_error, offsetof(UnitStatusInfo, load_error)                        },
+                { "Result",                         "s",               NULL,           offsetof(UnitStatusInfo, result)                            },
+                { "TriggeredBy",                    "as",              NULL,           offsetof(UnitStatusInfo, triggered_by)                      },
+                { "Triggers",                       "as",              NULL,           offsetof(UnitStatusInfo, triggers)                          },
+                { "InactiveExitTimestamp",          "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp)           },
+                { "InactiveExitTimestampMonotonic", "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
+                { "ActiveEnterTimestamp",           "t",               NULL,           offsetof(UnitStatusInfo, active_enter_timestamp)            },
+                { "ActiveExitTimestamp",            "t",               NULL,           offsetof(UnitStatusInfo, active_exit_timestamp)             },
+                { "InactiveEnterTimestamp",         "t",               NULL,           offsetof(UnitStatusInfo, inactive_enter_timestamp)          },
+                { "NeedDaemonReload",               "b",               NULL,           offsetof(UnitStatusInfo, need_daemon_reload)                },
+                { "Transient",                      "b",               NULL,           offsetof(UnitStatusInfo, transient)                         },
+                { "ExecMainPID",                    "u",               NULL,           offsetof(UnitStatusInfo, main_pid)                          },
+                { "MainPID",                        "u",               map_main_pid,   0                                                           },
+                { "ControlPID",                     "u",               NULL,           offsetof(UnitStatusInfo, control_pid)                       },
+                { "StatusText",                     "s",               NULL,           offsetof(UnitStatusInfo, status_text)                       },
+                { "PIDFile",                        "s",               NULL,           offsetof(UnitStatusInfo, pid_file)                          },
+                { "StatusErrno",                    "i",               NULL,           offsetof(UnitStatusInfo, status_errno)                      },
+                { "ExecMainStartTimestamp",         "t",               NULL,           offsetof(UnitStatusInfo, start_timestamp)                   },
+                { "ExecMainExitTimestamp",          "t",               NULL,           offsetof(UnitStatusInfo, exit_timestamp)                    },
+                { "ExecMainCode",                   "i",               NULL,           offsetof(UnitStatusInfo, exit_code)                         },
+                { "ExecMainStatus",                 "i",               NULL,           offsetof(UnitStatusInfo, exit_status)                       },
+                { "LogNamespace",                   "s",               NULL,           offsetof(UnitStatusInfo, log_namespace)                     },
+                { "ConditionTimestamp",             "t",               NULL,           offsetof(UnitStatusInfo, condition_timestamp)               },
+                { "ConditionResult",                "b",               NULL,           offsetof(UnitStatusInfo, condition_result)                  },
+                { "Conditions",                     "a(sbbsi)",        map_conditions, 0                                                           },
+                { "AssertTimestamp",                "t",               NULL,           offsetof(UnitStatusInfo, assert_timestamp)                  },
+                { "AssertResult",                   "b",               NULL,           offsetof(UnitStatusInfo, assert_result)                     },
+                { "Asserts",                        "a(sbbsi)",        map_asserts,    0                                                           },
+                { "NextElapseUSecRealtime",         "t",               NULL,           offsetof(UnitStatusInfo, next_elapse_real)                  },
+                { "NextElapseUSecMonotonic",        "t",               NULL,           offsetof(UnitStatusInfo, next_elapse_monotonic)             },
+                { "NAccepted",                      "u",               NULL,           offsetof(UnitStatusInfo, n_accepted)                        },
+                { "NConnections",                   "u",               NULL,           offsetof(UnitStatusInfo, n_connections)                     },
+                { "NRefused",                       "u",               NULL,           offsetof(UnitStatusInfo, n_refused)                         },
+                { "Accept",                         "b",               NULL,           offsetof(UnitStatusInfo, accept)                            },
+                { "Listen",                         "a(ss)",           map_listen,     offsetof(UnitStatusInfo, listen)                            },
+                { "SysFSPath",                      "s",               NULL,           offsetof(UnitStatusInfo, sysfs_path)                        },
+                { "Where",                          "s",               NULL,           offsetof(UnitStatusInfo, where)                             },
+                { "What",                           "s",               NULL,           offsetof(UnitStatusInfo, what)                              },
+                { "MemoryCurrent",                  "t",               NULL,           offsetof(UnitStatusInfo, memory_current)                    },
+                { "DefaultMemoryMin",               "t",               NULL,           offsetof(UnitStatusInfo, default_memory_min)                },
+                { "DefaultMemoryLow",               "t",               NULL,           offsetof(UnitStatusInfo, default_memory_low)                },
+                { "MemoryMin",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_min)                        },
+                { "MemoryLow",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_low)                        },
+                { "MemoryHigh",                     "t",               NULL,           offsetof(UnitStatusInfo, memory_high)                       },
+                { "MemoryMax",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_max)                        },
+                { "MemorySwapMax",                  "t",               NULL,           offsetof(UnitStatusInfo, memory_swap_max)                   },
+                { "MemoryLimit",                    "t",               NULL,           offsetof(UnitStatusInfo, memory_limit)                      },
+                { "CPUUsageNSec",                   "t",               NULL,           offsetof(UnitStatusInfo, cpu_usage_nsec)                    },
+                { "TasksCurrent",                   "t",               NULL,           offsetof(UnitStatusInfo, tasks_current)                     },
+                { "TasksMax",                       "t",               NULL,           offsetof(UnitStatusInfo, tasks_max)                         },
+                { "IPIngressBytes",                 "t",               NULL,           offsetof(UnitStatusInfo, ip_ingress_bytes)                  },
+                { "IPEgressBytes",                  "t",               NULL,           offsetof(UnitStatusInfo, ip_egress_bytes)                   },
+                { "IOReadBytes",                    "t",               NULL,           offsetof(UnitStatusInfo, io_read_bytes)                     },
+                { "IOWriteBytes",                   "t",               NULL,           offsetof(UnitStatusInfo, io_write_bytes)                    },
+                { "ExecCondition",                  "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecConditionEx",                "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecStartPre",                   "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStartPreEx",                 "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecStart",                      "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStartEx",                    "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecStartPost",                  "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStartPostEx",                "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecReload",                     "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecReloadEx",                   "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecStopPre",                    "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStop",                       "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStopEx",                     "a(sasasttttuii)", map_exec,       0                                                           },
+                { "ExecStopPost",                   "a(sasbttttuii)",  map_exec,       0                                                           },
+                { "ExecStopPostEx",                 "a(sasasttttuii)", map_exec,       0                                                           },
+                {}
+        };
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_set_free_ Set *found_properties = NULL;
+        _cleanup_(unit_status_info_free) UnitStatusInfo info = {
+                .memory_current = (uint64_t) -1,
+                .memory_high = CGROUP_LIMIT_MAX,
+                .memory_max = CGROUP_LIMIT_MAX,
+                .memory_swap_max = CGROUP_LIMIT_MAX,
+                .memory_limit = (uint64_t) -1,
+                .cpu_usage_nsec = (uint64_t) -1,
+                .tasks_current = (uint64_t) -1,
+                .tasks_max = (uint64_t) -1,
+                .ip_ingress_bytes = (uint64_t) -1,
+                .ip_egress_bytes = (uint64_t) -1,
+                .io_read_bytes = UINT64_MAX,
+                .io_write_bytes = UINT64_MAX,
+        };
+        char **pp;
+        int r;
+
+        assert(path);
+        assert(new_line);
+
+        log_debug("Showing one %s", path);
+
+        r = bus_map_all_properties(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        show_mode == SYSTEMCTL_SHOW_STATUS ? status_map : property_map,
+                        BUS_MAP_BOOLEAN_AS_BOOL,
+                        &error,
+                        &reply,
+                        &info);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
+
+        if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
+                log_full(show_mode == SYSTEMCTL_SHOW_STATUS ? LOG_ERR : LOG_DEBUG,
+                         "Unit %s could not be found.", unit);
+
+                if (show_mode == SYSTEMCTL_SHOW_STATUS)
+                        return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
+                else if (show_mode == SYSTEMCTL_SHOW_HELP)
+                        return -ENOENT;
+        }
+
+        if (*new_line)
+                printf("\n");
+
+        *new_line = true;
+
+        if (show_mode == SYSTEMCTL_SHOW_STATUS) {
+                print_status_info(bus, &info, ellipsized);
+
+                if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
+                        return EXIT_PROGRAM_NOT_RUNNING;
+
+                return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
+
+        } else if (show_mode == SYSTEMCTL_SHOW_HELP) {
+                show_unit_help(&info);
+                return 0;
+        }
+
+        r = sd_bus_message_rewind(reply, true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
+
+        r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_value, arg_all, &found_properties);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        STRV_FOREACH(pp, arg_properties)
+                if (!set_contains(found_properties, *pp))
+                        log_debug("Property %s does not exist.", *pp);
+
+        return 0;
+}
+
+static int get_unit_dbus_path_by_pid(
+                sd_bus *bus,
+                uint32_t pid,
+                char **unit) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        char *u;
+        int r;
+
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
+
+        r = sd_bus_message_read(reply, "o", &u);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        u = strdup(u);
+        if (!u)
+                return log_oom();
+
+        *unit = u;
+        return 0;
+}
+
+static int show_all(
+                sd_bus *bus,
+                bool *new_line,
+                bool *ellipsized) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        const UnitInfo *u;
+        unsigned c;
+        int r, ret = 0;
+
+        r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        c = (unsigned) r;
+
+        typesafe_qsort(unit_infos, c, unit_info_compare);
+
+        for (u = unit_infos; u < unit_infos + c; u++) {
+                _cleanup_free_ char *p = NULL;
+
+                p = unit_dbus_path_from_name(u->id);
+                if (!p)
+                        return log_oom();
+
+                r = show_one(bus, p, u->id, SYSTEMCTL_SHOW_STATUS, new_line, ellipsized);
+                if (r < 0)
+                        return r;
+                else if (r > 0 && ret == 0)
+                        ret = r;
+        }
+
+        return ret;
+}
+
+static int show_system_status(sd_bus *bus) {
+        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(machine_info_clear) struct machine_info mi = {};
+        _cleanup_free_ char *hn = NULL;
+        const char *on, *off;
+        int r;
+
+        hn = gethostname_malloc();
+        if (!hn)
+                return log_oom();
+
+        r = bus_map_all_properties(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        machine_info_property_map,
+                        BUS_MAP_STRDUP,
+                        &error,
+                        NULL,
+                        &mi);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
+
+        if (streq_ptr(mi.state, "degraded")) {
+                on = ansi_highlight_red();
+                off = ansi_normal();
+        } else if (streq_ptr(mi.state, "running")) {
+                on = ansi_highlight_green();
+                off = ansi_normal();
+        } else {
+                on = ansi_highlight_yellow();
+                off = ansi_normal();
+        }
+
+        printf("%s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
+
+        printf("    State: %s%s%s\n",
+               on, strna(mi.state), off);
+
+        printf("     Jobs: %" PRIu32 " queued\n", mi.n_jobs);
+        printf("   Failed: %" PRIu32 " units\n", mi.n_failed_units);
+
+        printf("    Since: %s; %s\n",
+               format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
+               format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
+
+        printf("   CGroup: %s\n", mi.control_group ?: "/");
+        if (IN_SET(arg_transport,
+                   BUS_TRANSPORT_LOCAL,
+                   BUS_TRANSPORT_MACHINE)) {
+                static const char prefix[] = "           ";
+                unsigned c;
+
+                c = columns();
+                if (c > sizeof(prefix) - 1)
+                        c -= sizeof(prefix) - 1;
+                else
+                        c = 0;
+
+                show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
+        }
+
+        return 0;
+}
+
+int show(int argc, char *argv[], void *userdata) {
+        bool new_line = false, ellipsized = false;
+        SystemctlShowMode show_mode;
+        int r, ret = 0;
+        sd_bus *bus;
+
+        assert(argv);
+
+        show_mode = systemctl_show_mode_from_string(argv[0]);
+        if (show_mode < 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Invalid argument.");
+
+        if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "'help' command expects one or more unit names.\n"
+                                       "(Alternatively, help for systemctl itself may be shown with --help)");
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        (void) pager_open(arg_pager_flags);
+
+        /* If no argument is specified inspect the manager itself */
+        if (show_mode == SYSTEMCTL_SHOW_PROPERTIES && argc <= 1)
+                return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
+
+        if (show_mode == SYSTEMCTL_SHOW_STATUS && argc <= 1) {
+
+                show_system_status(bus);
+                new_line = true;
+
+                if (arg_all)
+                        ret = show_all(bus, &new_line, &ellipsized);
+        } else {
+                _cleanup_free_ char **patterns = NULL;
+                char **name;
+
+                STRV_FOREACH(name, strv_skip(argv, 1)) {
+                        _cleanup_free_ char *path = NULL, *unit = NULL;
+                        uint32_t id;
+
+                        if (safe_atou32(*name, &id) < 0) {
+                                if (strv_push(&patterns, *name) < 0)
+                                        return log_oom();
+
+                                continue;
+                        } else if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) {
+                                /* Interpret as job id */
+                                if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
+                                        return log_oom();
+
+                        } else {
+                                /* Interpret as PID */
+                                r = get_unit_dbus_path_by_pid(bus, id, &path);
+                                if (r < 0) {
+                                        ret = r;
+                                        continue;
+                                }
+
+                                r = unit_name_from_dbus_path(path, &unit);
+                                if (r < 0)
+                                        return log_oom();
+                        }
+
+                        r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
+                        if (r < 0)
+                                return r;
+                        else if (r > 0 && ret == 0)
+                                ret = r;
+                }
+
+                if (!strv_isempty(patterns)) {
+                        _cleanup_strv_free_ char **names = NULL;
+
+                        r = expand_unit_names(bus, patterns, NULL, &names, NULL);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to expand names: %m");
+
+                        r = maybe_extend_with_unit_dependencies(bus, &names);
+                        if (r < 0)
+                                return r;
+
+                        STRV_FOREACH(name, names) {
+                                _cleanup_free_ char *path;
+
+                                path = unit_dbus_path_from_name(*name);
+                                if (!path)
+                                        return log_oom();
+
+                                r = show_one(bus, path, *name, show_mode, &new_line, &ellipsized);
+                                if (r < 0)
+                                        return r;
+                                if (r > 0 && ret == 0)
+                                        ret = r;
+                        }
+                }
+        }
+
+        if (ellipsized && !arg_quiet)
+                printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
+
+        return ret;
+}
diff --git a/src/systemctl/systemctl-show.h b/src/systemctl/systemctl-show.h
new file mode 100644 (file)
index 0000000..b4e5dda
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int show(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
new file mode 100644 (file)
index 0000000..46f58ff
--- /dev/null
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bootspec.h"
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "efivars.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "reboot-util.h"
+#include "systemctl-logind.h"
+#include "systemctl-start-special.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-trivial-method.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+static int load_kexec_kernel(void) {
+        _cleanup_(boot_config_free) BootConfig config = {};
+        _cleanup_free_ char *kernel = NULL, *initrd = NULL, *options = NULL;
+        const BootEntry *e;
+        pid_t pid;
+        int r;
+
+        if (kexec_loaded()) {
+                log_debug("Kexec kernel already loaded.");
+                return 0;
+        }
+
+        if (access(KEXEC, X_OK) < 0)
+                return log_error_errno(errno, KEXEC" is not available: %m");
+
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r == -ENOKEY)
+                /* The call doesn't log about ENOKEY, let's do so here. */
+                return log_error_errno(r,
+                                       "No kexec kernel loaded and autodetection failed.\n%s",
+                                       is_efi_boot()
+                                       ? "Cannot automatically load kernel: ESP partition mount point not found."
+                                       : "Automatic loading works only on systems booted with EFI.");
+        if (r < 0)
+                return r;
+
+        e = boot_config_default_entry(&config);
+        if (!e)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "No boot loader entry suitable as default, refusing to guess.");
+
+        log_debug("Found default boot loader entry in file \"%s\"", e->path);
+
+        if (!e->kernel)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Boot entry does not refer to Linux kernel, which is not supported currently.");
+        if (strv_length(e->initrd) > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Boot entry specifies multiple initrds, which is not supported currently.");
+
+        kernel = path_join(e->root, e->kernel);
+        if (!kernel)
+                return log_oom();
+
+        if (!strv_isempty(e->initrd)) {
+                initrd = path_join(e->root, e->initrd[0]);
+                if (!initrd)
+                        return log_oom();
+        }
+
+        options = strv_join(e->options, " ");
+        if (!options)
+                return log_oom();
+
+        log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+                 "%s "KEXEC" --load \"%s\" --append \"%s\"%s%s%s",
+                 arg_dry_run ? "Would run" : "Running",
+                 kernel,
+                 options,
+                 initrd ? " --initrd \"" : NULL, strempty(initrd), initrd ? "\"" : "");
+        if (arg_dry_run)
+                return 0;
+
+        r = safe_fork("(kexec)", FORK_WAIT|FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                const char* const args[] = {
+                        KEXEC,
+                        "--load", kernel,
+                        "--append", options,
+                        initrd ? "--initrd" : NULL, initrd,
+                        NULL
+                };
+
+                /* Child */
+                execv(args[0], (char * const *) args);
+                _exit(EXIT_FAILURE);
+        }
+
+        return 0;
+}
+
+static int set_exit_code(uint8_t code) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_call_method(bus, bus_systemd_mgr, "SetExitCode", &error, NULL, "y", code);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+int start_special(int argc, char *argv[], void *userdata) {
+        bool termination_action; /* An action that terminates the manager, can be performed also by
+                                  * signal. */
+        enum action a;
+        int r;
+
+        assert(argv);
+
+        a = verb_to_action(argv[0]);
+
+        r = logind_check_inhibitors(a);
+        if (r < 0)
+                return r;
+
+        if (arg_force >= 2) {
+                r = must_be_root();
+                if (r < 0)
+                        return r;
+        }
+
+        r = prepare_firmware_setup();
+        if (r < 0)
+                return r;
+
+        r = prepare_boot_loader_menu();
+        if (r < 0)
+                return r;
+
+        r = prepare_boot_loader_entry();
+        if (r < 0)
+                return r;
+
+        if (a == ACTION_REBOOT) {
+                const char *arg = NULL;
+
+                if (argc > 1) {
+                        if (arg_reboot_argument)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Both --reboot-argument= and positional argument passed to reboot command, refusing.");
+
+                        log_notice("Positional argument to reboot command is deprecated, please use --reboot-argument= instead. Accepting anyway.");
+                        arg = argv[1];
+                } else
+                        arg = arg_reboot_argument;
+
+                if (arg) {
+                        r = update_reboot_parameter_and_warn(arg, false);
+                        if (r < 0)
+                                return r;
+                }
+
+        } else if (a == ACTION_KEXEC) {
+                r = load_kexec_kernel();
+                if (r < 0 && arg_force >= 1)
+                        log_notice("Failed to load kexec kernel, continuing without.");
+                else if (r < 0)
+                        return r;
+
+        } else if (a == ACTION_EXIT && argc > 1) {
+                uint8_t code;
+
+                /* If the exit code is not given on the command line, don't reset it to zero: just keep it as
+                 * it might have been set previously. */
+
+                r = safe_atou8(argv[1], &code);
+                if (r < 0)
+                        return log_error_errno(r, "Invalid exit code.");
+
+                r = set_exit_code(code);
+                if (r < 0)
+                        return r;
+        }
+
+        termination_action = IN_SET(a,
+                                    ACTION_HALT,
+                                    ACTION_POWEROFF,
+                                    ACTION_REBOOT);
+        if (termination_action && arg_force >= 2)
+                return halt_now(a);
+
+        if (arg_force >= 1 &&
+            (termination_action || IN_SET(a, ACTION_KEXEC, ACTION_EXIT)))
+                r = trivial_method(argc, argv, userdata);
+        else {
+                /* First try logind, to allow authentication with polkit */
+                if (IN_SET(a,
+                           ACTION_POWEROFF,
+                           ACTION_REBOOT,
+                           ACTION_HALT,
+                           ACTION_SUSPEND,
+                           ACTION_HIBERNATE,
+                           ACTION_HYBRID_SLEEP,
+                           ACTION_SUSPEND_THEN_HIBERNATE)) {
+
+                        r = logind_reboot(a);
+                        if (r >= 0)
+                                return r;
+                        if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+                                /* Requested operation is not supported or already in progress */
+                                return r;
+
+                        /* On all other errors, try low-level operation. In order to minimize the difference
+                         * between operation with and without logind, we explicitly enable non-blocking mode
+                         * for this, as logind's shutdown operations are always non-blocking. */
+
+                        arg_no_block = true;
+
+                } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
+                        /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make
+                         * them asynchronous, in order to not confuse the user needlessly with unexpected
+                         * behaviour. */
+                        arg_no_block = true;
+
+                r = start_unit(argc, argv, userdata);
+        }
+
+        if (termination_action && arg_force < 2 &&
+            IN_SET(r, -ENOENT, -ETIMEDOUT))
+                log_notice("It is possible to perform action directly, see discussion of --force --force in man:systemctl(1).");
+
+        return r;
+}
+
+int start_system_special(int argc, char *argv[], void *userdata) {
+        /* Like start_special above, but raises an error when running in user mode */
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Bad action for %s mode.",
+                                       arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
+
+        return start_special(argc, argv, userdata);
+}
diff --git a/src/systemctl/systemctl-start-special.h b/src/systemctl/systemctl-start-special.h
new file mode 100644 (file)
index 0000000..43a31ba
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int start_special(int argc, char *argv[], void *userdata);
+int start_system_special(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c
new file mode 100644 (file)
index 0000000..bd78568
--- /dev/null
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "sd-bus.h"
+
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-util.h"
+#include "bus-wait-for-jobs.h"
+#include "bus-wait-for-units.h"
+#include "macro.h"
+#include "special.h"
+#include "string-util.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static const struct {
+        const char *verb;      /* systemctl verb */
+        const char *method;    /* Name of the specific D-Bus method */
+        const char *job_type;  /* Job type when passing to the generic EnqueueUnitJob() method */
+} unit_actions[] = {
+        { "start",                 "StartUnit",              "start"                 },
+        { "stop",                  "StopUnit",               "stop"                  },
+        { "condstop",              "StopUnit",               "stop"                  }, /* legacy alias */
+        { "reload",                "ReloadUnit",             "reload"                },
+        { "restart",               "RestartUnit",            "restart"               },
+        { "try-restart",           "TryRestartUnit",         "try-restart"           },
+        { "condrestart",           "TryRestartUnit",         "try-restart"           }, /* legacy alias */
+        { "reload-or-restart",     "ReloadOrRestartUnit",    "reload-or-restart"     },
+        { "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
+        { "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+        { "condreload",            "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+        { "force-reload",          "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+};
+
+static const char *verb_to_method(const char *verb) {
+       size_t i;
+
+       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+                if (streq_ptr(unit_actions[i].verb, verb))
+                        return unit_actions[i].method;
+
+       return "StartUnit";
+}
+
+static const char *verb_to_job_type(const char *verb) {
+       size_t i;
+
+       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+                if (streq_ptr(unit_actions[i].verb, verb))
+                        return unit_actions[i].job_type;
+
+       return "start";
+}
+
+static int start_unit_one(
+                sd_bus *bus,
+                const char *method,    /* When using classic per-job bus methods */
+                const char *job_type,  /* When using new-style EnqueueUnitJob() */
+                const char *name,
+                const char *mode,
+                sd_bus_error *error,
+                BusWaitForJobs *w,
+                BusWaitForUnits *wu) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        const char *path;
+        bool done = false;
+        int r;
+
+        assert(method);
+        assert(name);
+        assert(mode);
+        assert(error);
+
+        log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
+                  arg_dry_run ? "Would execute" : "Executing",
+                  method, name, mode);
+
+        if (arg_dry_run)
+                return 0;
+
+        if (arg_show_transaction) {
+                _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
+
+                /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
+                r = bus_call_method(
+                                bus,
+                                bus_systemd_mgr,
+                                "EnqueueUnitJob",
+                                &enqueue_error,
+                                &reply,
+                                "sss",
+                                name, job_type, mode);
+                if (r < 0) {
+                        if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                                (void) sd_bus_error_move(error, &enqueue_error);
+                                goto fail;
+                        }
+
+                        /* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
+                        log_notice("--show-transaction not supported by this service manager, proceeding without.");
+                } else {
+                        const char *u, *jt;
+                        uint32_t id;
+
+                        r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
+
+                        r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+                        for (;;) {
+                                r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+                                if (r == 0)
+                                        break;
+
+                                log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
+                        }
+
+                        r = sd_bus_message_exit_container(reply);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        done = true;
+                }
+        }
+
+        if (!done) {
+                r = bus_call_method(bus, bus_systemd_mgr, method, error, &reply, "ss", name, mode);
+                if (r < 0)
+                        goto fail;
+
+                r = sd_bus_message_read(reply, "o", &path);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+        }
+
+        if (need_daemon_reload(bus, name) > 0)
+                warn_unit_file_changed(name);
+
+        if (w) {
+                log_debug("Adding %s to the set", path);
+                r = bus_wait_for_jobs_add(w, path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to watch job for %s: %m", name);
+        }
+
+        if (wu) {
+                r = bus_wait_for_units_add_unit(wu, name, BUS_WAIT_FOR_INACTIVE|BUS_WAIT_NO_JOB, NULL, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to watch unit %s: %m", name);
+        }
+
+        return 0;
+
+fail:
+        /* There's always a fallback possible for legacy actions. */
+        if (arg_action != ACTION_SYSTEMCTL)
+                return r;
+
+        log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
+
+        if (!sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT,
+                                           BUS_ERROR_UNIT_MASKED,
+                                           BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
+                log_error("See %s logs and 'systemctl%s status%s %s' for details.",
+                          arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
+                          arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+                          name[0] == '-' ? " --" : "",
+                          name);
+
+        return r;
+}
+
+const struct action_metadata action_table[_ACTION_MAX] = {
+        [ACTION_HALT]                   = { SPECIAL_HALT_TARGET,                   "halt",                   "replace-irreversibly" },
+        [ACTION_POWEROFF]               = { SPECIAL_POWEROFF_TARGET,               "poweroff",               "replace-irreversibly" },
+        [ACTION_REBOOT]                 = { SPECIAL_REBOOT_TARGET,                 "reboot",                 "replace-irreversibly" },
+        [ACTION_KEXEC]                  = { SPECIAL_KEXEC_TARGET,                  "kexec",                  "replace-irreversibly" },
+        [ACTION_RUNLEVEL2]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL3]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL4]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL5]              = { SPECIAL_GRAPHICAL_TARGET,              NULL,                     "isolate"              },
+        [ACTION_RESCUE]                 = { SPECIAL_RESCUE_TARGET,                 "rescue",                 "isolate"              },
+        [ACTION_EMERGENCY]              = { SPECIAL_EMERGENCY_TARGET,              "emergency",              "isolate"              },
+        [ACTION_DEFAULT]                = { SPECIAL_DEFAULT_TARGET,                "default",                "isolate"              },
+        [ACTION_EXIT]                   = { SPECIAL_EXIT_TARGET,                   "exit",                   "replace-irreversibly" },
+        [ACTION_SUSPEND]                = { SPECIAL_SUSPEND_TARGET,                "suspend",                "replace-irreversibly" },
+        [ACTION_HIBERNATE]              = { SPECIAL_HIBERNATE_TARGET,              "hibernate",              "replace-irreversibly" },
+        [ACTION_HYBRID_SLEEP]           = { SPECIAL_HYBRID_SLEEP_TARGET,           "hybrid-sleep",           "replace-irreversibly" },
+        [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
+};
+
+enum action verb_to_action(const char *verb) {
+        enum action i;
+
+        for (i = 0; i < _ACTION_MAX; i++)
+                if (streq_ptr(action_table[i].verb, verb))
+                        return i;
+
+        return _ACTION_INVALID;
+}
+
+static const char** make_extra_args(const char *extra_args[static 4]) {
+        size_t n = 0;
+
+        assert(extra_args);
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                extra_args[n++] = "--user";
+
+        if (arg_transport == BUS_TRANSPORT_REMOTE) {
+                extra_args[n++] = "-H";
+                extra_args[n++] = arg_host;
+        } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+                extra_args[n++] = "-M";
+                extra_args[n++] = arg_host;
+        } else
+                assert(arg_transport == BUS_TRANSPORT_LOCAL);
+
+        extra_args[n] = NULL;
+        return extra_args;
+}
+
+int start_unit(int argc, char *argv[], void *userdata) {
+        _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *wu = NULL;
+        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
+        const char *method, *job_type, *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;
+        char **name;
+
+        if (arg_wait && !STR_IN_SET(argv[0], "start", "restart"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--wait may only be used with the 'start' or 'restart' commands.");
+
+        /* We cannot do sender tracking on the private bus, so we need the full one for RefUnit to implement
+         * --wait */
+        r = acquire_bus(arg_wait ? BUS_FULL : BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        ask_password_agent_open_maybe();
+        polkit_agent_open_maybe();
+
+        if (arg_action == ACTION_SYSTEMCTL) {
+                enum action action;
+
+                action = verb_to_action(argv[0]);
+
+                if (action != _ACTION_INVALID) {
+                        /* A command in style "systemctl reboot", "systemctl poweroff", … */
+                        method = "StartUnit";
+                        job_type = "start";
+                        mode = action_table[action].mode;
+                        one_name = action_table[action].target;
+                } else {
+                        if (streq(argv[0], "isolate")) {
+                                /* A "systemctl isolate <unit1> <unit2> …" command */
+                                method = "StartUnit";
+                                job_type = "start";
+                                mode = "isolate";
+                                suffix = ".target";
+                        } else {
+                                /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
+                                method = verb_to_method(argv[0]);
+                                job_type = verb_to_job_type(argv[0]);
+                                mode = arg_job_mode;
+                        }
+                        one_name = NULL;
+                }
+        } else {
+                /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
+                assert(arg_action >= 0 && arg_action < _ACTION_MAX);
+                assert(action_table[arg_action].target);
+                assert(action_table[arg_action].mode);
+
+                method = "StartUnit";
+                job_type = "start";
+                mode = action_table[arg_action].mode;
+                one_name = action_table[arg_action].target;
+        }
+
+        if (one_name) {
+                names = strv_new(one_name);
+                if (!names)
+                        return log_oom();
+        } else {
+                bool expanded;
+
+                r = expand_unit_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to expand names: %m");
+
+                if (!arg_all && expanded && streq(job_type, "start") && !arg_quiet) {
+                        log_warning("Warning: %ssystemctl start called with a glob pattern.%s",
+                                    ansi_highlight_red(),
+                                    ansi_normal());
+                        log_notice("Hint: unit globs expand to loaded units, so start will usually have no effect.\n"
+                                   "      Passing --all will also load units which are pulled in by other units.\n"
+                                   "      See systemctl(1) for more details.");
+                }
+        }
+
+        if (!arg_no_block) {
+                r = bus_wait_for_jobs_new(bus, &w);
+                if (r < 0)
+                        return log_error_errno(r, "Could not watch jobs: %m");
+        }
+
+        if (arg_wait) {
+                r = bus_call_method_async(bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable subscription: %m");
+
+                r = bus_wait_for_units_new(bus, &wu);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to allocate unit watch context: %m");
+        }
+
+        STRV_FOREACH(name, names) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
+                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) {
+                const char* extra_args[4];
+
+                r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
+                if (r < 0)
+                        return r;
+
+                /* When stopping units, warn if they can still be triggered by
+                 * another active unit (socket, path, timer) */
+                if (!arg_quiet)
+                        STRV_FOREACH(name, stopped_units)
+                                (void) check_triggering_units(bus, *name);
+        }
+
+        if (arg_wait) {
+                r = bus_wait_for_units_run(wu);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to wait for units: %m");
+                if (r == BUS_WAIT_FAILURE && ret == EXIT_SUCCESS)
+                        ret = EXIT_FAILURE;
+        }
+
+        return ret;
+}
diff --git a/src/systemctl/systemctl-start-unit.h b/src/systemctl/systemctl-start-unit.h
new file mode 100644 (file)
index 0000000..3f82740
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "systemctl.h"
+
+int start_unit(int argc, char *argv[], void *userdata);
+
+struct action_metadata {
+        const char *target;
+        const char *verb;
+        const char *mode;
+};
+
+extern const struct action_metadata action_table[_ACTION_MAX];
+
+enum action verb_to_action(const char *verb);
diff --git a/src/systemctl/systemctl-switch-root.c b/src/systemctl/systemctl-switch-root.c
new file mode 100644 (file)
index 0000000..ebcc66a
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
+#include "signal-util.h"
+#include "stat-util.h"
+#include "systemctl-switch-root.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+int switch_root(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *cmdline_init = NULL;
+        const char *root, *init;
+        sd_bus *bus;
+        int r;
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch root remotely.");
+
+        if (argc < 2 || argc > 3)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments.");
+
+        root = argv[1];
+
+        if (argc >= 3)
+                init = argv[2];
+        else {
+                r = proc_cmdline_get_key("init", 0, &cmdline_init);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
+
+                init = cmdline_init;
+        }
+
+        init = empty_to_null(init);
+        if (init) {
+                const char *root_systemd_path = NULL, *root_init_path = NULL;
+
+                root_systemd_path = prefix_roota(root, "/" SYSTEMD_BINARY_PATH);
+                root_init_path = prefix_roota(root, init);
+
+                /* If the passed init is actually the same as the systemd binary, then let's suppress it. */
+                if (files_same(root_init_path, root_systemd_path, 0) > 0)
+                        init = NULL;
+        }
+
+        /* Instruct PID1 to exclude us from its killing spree applied during the transition. Otherwise we
+         * would exit with a failure status even though the switch to the new root has succeed. */
+        assert(saved_argv);
+        assert(saved_argv[0]);
+        saved_argv[0][0] = '@';
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        /* If we are slow to exit after the root switch, the new systemd instance will send us a signal to
+         * terminate. Just ignore it and exit normally.  This way the unit does not end up as failed. */
+        r = ignore_signals(SIGTERM, -1);
+        if (r < 0)
+                log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
+
+        log_debug("Switching root - root: %s; init: %s", root, strna(init));
+
+        r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
+        if (r < 0) {
+                (void) default_signals(SIGTERM, -1);
+
+                return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
+        }
+
+        return 0;
+}
diff --git a/src/systemctl/systemctl-switch-root.h b/src/systemctl/systemctl-switch-root.h
new file mode 100644 (file)
index 0000000..47ed852
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int switch_root(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c
new file mode 100644 (file)
index 0000000..2dca9e4
--- /dev/null
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "env-util.h"
+#include "fd-util.h"
+#include "initreq.h"
+#include "install.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "strv.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl.h"
+
+int talk_initctl(char rl) {
+#if HAVE_SYSV_COMPAT
+        struct init_request request;
+        _cleanup_close_ int fd = -1;
+        const char *p;
+        int r;
+
+        /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this
+         * system, and > 0 on success. */
+
+        if (rl == 0)
+                return 0;
+
+        FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
+                fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+                if (fd >= 0 || errno != ENOENT)
+                        break;
+        }
+        if (fd < 0) {
+                if (errno == ENOENT)
+                        return 0;
+
+                return log_error_errno(errno, "Failed to open initctl fifo: %m");
+        }
+
+        request = (struct init_request) {
+                .magic = INIT_MAGIC,
+                .sleeptime = 0,
+                .cmd = INIT_CMD_RUNLVL,
+                .runlevel = rl,
+        };
+
+        r = loop_write(fd, &request, sizeof(request), false);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write to %s: %m", p);
+
+        return 1;
+#else
+        return -EOPNOTSUPP;
+#endif
+}
+
+int parse_shutdown_time_spec(const char *t, usec_t *ret) {
+        assert(t);
+        assert(ret);
+
+        if (streq(t, "now"))
+                *ret = 0;
+        else if (!strchr(t, ':')) {
+                uint64_t u;
+
+                if (safe_atou64(t, &u) < 0)
+                        return -EINVAL;
+
+                *ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
+        } else {
+                char *e = NULL;
+                long hour, minute;
+                struct tm tm = {};
+                time_t s;
+                usec_t n;
+
+                errno = 0;
+                hour = strtol(t, &e, 10);
+                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
+                        return -EINVAL;
+
+                minute = strtol(e+1, &e, 10);
+                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
+                        return -EINVAL;
+
+                n = now(CLOCK_REALTIME);
+                s = (time_t) (n / USEC_PER_SEC);
+
+                assert_se(localtime_r(&s, &tm));
+
+                tm.tm_hour = (int) hour;
+                tm.tm_min = (int) minute;
+                tm.tm_sec = 0;
+
+                s = mktime(&tm);
+                assert(s >= 0);
+
+                *ret = (usec_t) s * USEC_PER_SEC;
+
+                while (*ret <= n)
+                        *ret += USEC_PER_DAY;
+        }
+
+        return 0;
+}
+
+int enable_sysv_units(const char *verb, char **args) {
+        int r = 0;
+
+#if HAVE_SYSV_COMPAT
+        _cleanup_(lookup_paths_free) LookupPaths paths = {};
+        unsigned f = 0;
+
+        /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                return 0;
+
+        if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
+                return 0;
+
+        if (!STR_IN_SET(verb,
+                        "enable",
+                        "disable",
+                        "is-enabled"))
+                return 0;
+
+        r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
+        if (r < 0)
+                return r;
+
+        r = 0;
+        while (args[f]) {
+
+                const char *argv[] = {
+                        ROOTLIBEXECDIR "/systemd-sysv-install",
+                        NULL, /* --root= */
+                        NULL, /* verb */
+                        NULL, /* service */
+                        NULL,
+                };
+
+                _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL, *v = NULL;
+                bool found_native = false, found_sysv;
+                const char *name;
+                unsigned c = 1;
+                pid_t pid;
+                int j;
+
+                name = args[f++];
+
+                if (!endswith(name, ".service"))
+                        continue;
+
+                if (path_is_absolute(name))
+                        continue;
+
+                j = unit_file_exists(arg_scope, &paths, name);
+                if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
+                        return log_error_errno(j, "Failed to look up unit file state: %m");
+                found_native = j != 0;
+
+                /* If we have both a native unit and a SysV script, enable/disable them both (below); for
+                 * is-enabled, prefer the native unit */
+                if (found_native && streq(verb, "is-enabled"))
+                        continue;
+
+                p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
+                if (!p)
+                        return log_oom();
+
+                p[strlen(p) - STRLEN(".service")] = 0;
+                found_sysv = access(p, F_OK) >= 0;
+                if (!found_sysv)
+                        continue;
+
+                if (!arg_quiet) {
+                        if (found_native)
+                                log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
+                        else
+                                log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
+                }
+
+                if (!isempty(arg_root)) {
+                        q = strjoin("--root=", arg_root);
+                        if (!q)
+                                return log_oom();
+
+                        argv[c++] = q;
+                }
+
+                /* Let's copy the verb, since it's still pointing directly into the original argv[] array we
+                 * got passed, but safe_fork() is likely going to rewrite that for the new child */
+                v = strdup(verb);
+                if (!v)
+                        return log_oom();
+
+                argv[c++] = v;
+                argv[c++] = basename(p);
+                argv[c] = NULL;
+
+                l = strv_join((char**)argv, " ");
+                if (!l)
+                        return log_oom();
+
+                if (!arg_quiet)
+                        log_info("Executing: %s", l);
+
+                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) {
+                        /* Child */
+                        execv(argv[0], (char**) argv);
+                        log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
+                        _exit(EXIT_FAILURE);
+                }
+
+                j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
+                if (j < 0)
+                        return j;
+                if (streq(verb, "is-enabled")) {
+                        if (j == EXIT_SUCCESS) {
+                                if (!arg_quiet)
+                                        puts("enabled");
+                                r = 1;
+                        } else {
+                                if (!arg_quiet)
+                                        puts("disabled");
+                        }
+
+                } else if (j != EXIT_SUCCESS)
+                        return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
+
+                if (found_native)
+                        continue;
+
+                /* Remove this entry, so that we don't try enabling it as native unit */
+                assert(f > 0);
+                f--;
+                assert(args[f] == name);
+                strv_remove(args + f, name);
+        }
+
+#endif
+        return r;
+}
+
+int action_to_runlevel(void) {
+#if HAVE_SYSV_COMPAT
+        static const char table[_ACTION_MAX] = {
+                [ACTION_HALT] =      '0',
+                [ACTION_POWEROFF] =  '0',
+                [ACTION_REBOOT] =    '6',
+                [ACTION_RUNLEVEL2] = '2',
+                [ACTION_RUNLEVEL3] = '3',
+                [ACTION_RUNLEVEL4] = '4',
+                [ACTION_RUNLEVEL5] = '5',
+                [ACTION_RESCUE] =    '1'
+        };
+
+        assert(arg_action >= 0 && arg_action < _ACTION_MAX);
+        return table[arg_action];
+#else
+        return -EOPNOTSUPP;
+#endif
+}
similarity index 92%
rename from src/systemctl/sysv-compat.h
rename to src/systemctl/systemctl-sysv-compat.h
index e79919217ca3fd319b74f47166d3a15dcd9114f0..9a3b84dedaf7c0d9865f0ba4c68c8c26c228c5f5 100644 (file)
@@ -3,9 +3,7 @@
 
 #include "time-util.h"
 
-#if HAVE_SYSV_COMPAT
 int talk_initctl(char runlevel);
-#endif
 
 int parse_shutdown_time_spec(const char *t, usec_t *ret);
 
@@ -31,3 +29,7 @@ enum {
         EXIT_PROGRAM_NOT_RUNNING                  = 3,
         EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN   = 4,
 };
+
+int enable_sysv_units(const char *verb, char **args);
+
+int action_to_runlevel(void) _pure_;
diff --git a/src/systemctl/systemctl-trivial-method.c b/src/systemctl/systemctl-trivial-method.c
new file mode 100644 (file)
index 0000000..1f1181f
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "systemctl-trivial-method.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+
+/* A generic implementation for cases we just need to invoke a simple method call on the Manager object. */
+
+int trivial_method(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *method;
+        sd_bus *bus;
+        int r;
+
+        if (arg_dry_run)
+                return 0;
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        polkit_agent_open_maybe();
+
+        method =
+                streq(argv[0], "clear-jobs")    ||
+                streq(argv[0], "cancel")        ? "ClearJobs" :
+                streq(argv[0], "reset-failed")  ? "ResetFailed" :
+                streq(argv[0], "halt")          ? "Halt" :
+                streq(argv[0], "reboot")        ? "Reboot" :
+                streq(argv[0], "kexec")         ? "KExec" :
+                streq(argv[0], "exit")          ? "Exit" :
+                             /* poweroff */       "PowerOff";
+
+        r = bus_call_method(bus, bus_systemd_mgr, method, &error, NULL, NULL);
+        if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+                return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+
+        /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support
+         * fallbacks to the old ways of doing things, hence don't log any error in that case here. */
+
+        return r < 0 ? r : 0;
+}
diff --git a/src/systemctl/systemctl-trivial-method.h b/src/systemctl/systemctl-trivial-method.h
new file mode 100644 (file)
index 0000000..044540b
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int trivial_method(int argc, char *argv[], void *userdata);
diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c
new file mode 100644 (file)
index 0000000..603b1ea
--- /dev/null
@@ -0,0 +1,936 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/reboot.h>
+#include <unistd.h>
+
+#include "sd-bus.h"
+#include "sd-daemon.h"
+
+#include "bus-common-errors.h"
+#include "bus-locator.h"
+#include "bus-map-properties.h"
+#include "bus-unit-util.h"
+#include "dropin.h"
+#include "env-util.h"
+#include "exit-status.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "macro.h"
+#include "path-util.h"
+#include "reboot-util.h"
+#include "set.h"
+#include "spawn-ask-password-agent.h"
+#include "spawn-polkit-agent.h"
+#include "stat-util.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "verbs.h"
+
+static sd_bus *buses[_BUS_FOCUS_MAX] = {};
+
+int acquire_bus(BusFocus focus, sd_bus **ret) {
+        int r;
+
+        assert(focus < _BUS_FOCUS_MAX);
+        assert(ret);
+
+        /* We only go directly to the manager, if we are using a local transport */
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                focus = BUS_FULL;
+
+        if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
+                focus = BUS_FULL;
+
+        if (!buses[focus]) {
+                bool user;
+
+                user = arg_scope != UNIT_FILE_SYSTEM;
+
+                if (focus == BUS_MANAGER)
+                        r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
+                else
+                        r = bus_connect_transport(arg_transport, arg_host, user, &buses[focus]);
+                if (r < 0)
+                        return bus_log_connect_error(r);
+
+                (void) sd_bus_set_allow_interactive_authorization(buses[focus], arg_ask_password);
+        }
+
+        *ret = buses[focus];
+        return 0;
+}
+
+void release_busses(void) {
+        BusFocus w;
+
+        for (w = 0; w < _BUS_FOCUS_MAX; w++)
+                buses[w] = sd_bus_flush_close_unref(buses[w]);
+}
+
+void ask_password_agent_open_maybe(void) {
+        /* Open the password agent as a child process if necessary */
+
+        if (arg_dry_run)
+                return;
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                return;
+
+        ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
+}
+
+void polkit_agent_open_maybe(void) {
+        /* Open the polkit agent as a child process if necessary */
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                return;
+
+        polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+}
+
+int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
+        assert(error);
+
+        if (!sd_bus_error_is_set(error))
+                return r;
+
+        if (sd_bus_error_has_names(error, SD_BUS_ERROR_ACCESS_DENIED,
+                                          BUS_ERROR_ONLY_BY_DEPENDENCY,
+                                          BUS_ERROR_NO_ISOLATION,
+                                          BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
+                return EXIT_NOPERMISSION;
+
+        if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
+                return EXIT_NOTINSTALLED;
+
+        if (sd_bus_error_has_names(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
+                                          SD_BUS_ERROR_NOT_SUPPORTED))
+                return EXIT_NOTIMPLEMENTED;
+
+        if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
+                return EXIT_NOTCONFIGURED;
+
+        if (r != 0)
+                return r;
+
+        return EXIT_FAILURE;
+}
+
+int get_state_one_unit(sd_bus *bus, const char *unit, UnitActiveState *ret_active_state) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *buf = NULL, *dbus_path = NULL;
+        UnitActiveState state;
+        int r;
+
+        assert(unit);
+        assert(ret_active_state);
+
+        dbus_path = unit_dbus_path_from_name(unit);
+        if (!dbus_path)
+                return log_oom();
+
+        r = sd_bus_get_property_string(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        dbus_path,
+                        "org.freedesktop.systemd1.Unit",
+                        "ActiveState",
+                        &error,
+                        &buf);
+        if (r < 0)
+                return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
+
+        state = unit_active_state_from_string(buf);
+        if (state < 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit state '%s' for: %s", buf, unit);
+
+        *ret_active_state = state;
+        return 0;
+}
+
+int get_unit_list(
+                sd_bus *bus,
+                const char *machine,
+                char **patterns,
+                UnitInfo **unit_infos,
+                int c,
+                sd_bus_message **ret_reply) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        size_t size = c;
+        int r;
+        bool fallback = false;
+
+        assert(bus);
+        assert(unit_infos);
+        assert(ret_reply);
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, arg_states);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, patterns);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, &reply);
+        if (r < 0 && (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
+                                                     SD_BUS_ERROR_ACCESS_DENIED))) {
+                /* Fallback to legacy ListUnitsFiltered method */
+                fallback = true;
+                log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
+                m = sd_bus_message_unref(m);
+                sd_bus_error_free(&error);
+
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, arg_states);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+        }
+        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 u;
+
+                r = bus_parse_unit_info(reply, &u);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+                if (r == 0)
+                        break;
+
+                u.machine = machine;
+
+                if (!output_show_unit(&u, fallback ? patterns : NULL))
+                        continue;
+
+                if (!GREEDY_REALLOC(*unit_infos, size, c+1))
+                        return log_oom();
+
+                (*unit_infos)[c++] = u;
+        }
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        *ret_reply = TAKE_PTR(reply);
+        return c;
+}
+
+int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
+        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
+        char **name;
+        int r, i;
+
+        assert(bus);
+        assert(ret);
+
+        STRV_FOREACH(name, names) {
+                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
+                char *t;
+
+                r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle name: %m");
+
+                if (string_is_glob(t))
+                        r = strv_consume(&globs, t);
+                else
+                        r = strv_consume(&mangled, t);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        /* Query the manager only if any of the names are a glob, since this is fairly expensive */
+        bool expanded = !strv_isempty(globs);
+        if (expanded) {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_free_ UnitInfo *unit_infos = NULL;
+                size_t allocated, n;
+
+                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
+                if (r < 0)
+                        return r;
+
+                n = strv_length(mangled);
+                allocated = n + 1;
+
+                for (i = 0; i < r; i++) {
+                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
+                                return log_oom();
+
+                        mangled[n] = strdup(unit_infos[i].id);
+                        if (!mangled[n])
+                                return log_oom();
+
+                        mangled[++n] = NULL;
+                }
+        }
+
+        if (ret_expanded)
+                *ret_expanded = expanded;
+
+        *ret = TAKE_PTR(mangled);
+        return 0;
+}
+
+int check_triggering_units(sd_bus *bus, const char *unit) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *n = NULL, *dbus_path = NULL, *load_state = NULL;
+        _cleanup_strv_free_ char **triggered_by = NULL;
+        bool print_warning_label = true;
+        UnitActiveState active_state;
+        char **i;
+        int r;
+
+        r = unit_name_mangle(unit, 0, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
+
+        r = unit_load_state(bus, n, &load_state);
+        if (r < 0)
+                return r;
+
+        if (streq(load_state, "masked"))
+                return 0;
+
+        dbus_path = unit_dbus_path_from_name(n);
+        if (!dbus_path)
+                return log_oom();
+
+        r = sd_bus_get_property_strv(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        dbus_path,
+                        "org.freedesktop.systemd1.Unit",
+                        "TriggeredBy",
+                        &error,
+                        &triggered_by);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
+
+        STRV_FOREACH(i, triggered_by) {
+                r = get_state_one_unit(bus, *i, &active_state);
+                if (r < 0)
+                        return r;
+
+                if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
+                        continue;
+
+                if (print_warning_label) {
+                        log_warning("Warning: Stopping %s, but it can still be activated by:", n);
+                        print_warning_label = false;
+                }
+
+                log_warning("  %s", *i);
+        }
+
+        return 0;
+}
+
+int need_daemon_reload(sd_bus *bus, const char *unit) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        const char *path;
+        int b, r;
+
+        /* We ignore all errors here, since this is used to show a
+         * warning only */
+
+        /* We don't use unit_dbus_path_from_name() directly since we
+         * don't want to load the unit if it isn't loaded. */
+
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(reply, "o", &path);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Unit",
+                        "NeedDaemonReload",
+                        NULL,
+                        'b', &b);
+        if (r < 0)
+                return r;
+
+        return b;
+}
+
+void warn_unit_file_changed(const char *unit) {
+        assert(unit);
+
+        log_warning("%sWarning:%s The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
+                    ansi_highlight_red(),
+                    ansi_normal(),
+                    unit,
+                    arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+}
+
+int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
+        char **p;
+
+        assert(lp);
+        assert(unit_name);
+
+        STRV_FOREACH(p, lp->search_path) {
+                _cleanup_free_ char *path = NULL, *lpath = NULL;
+                int r;
+
+                path = path_join(*p, unit_name);
+                if (!path)
+                        return log_oom();
+
+                r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
+                if (r == -ENOENT)
+                        continue;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0)
+                        return log_error_errno(r, "Failed to access path \"%s\": %m", path);
+
+                if (ret_unit_path)
+                        *ret_unit_path = TAKE_PTR(lpath);
+
+                return 1;
+        }
+
+        if (ret_unit_path)
+                *ret_unit_path = NULL;
+
+        return 0;
+}
+
+int unit_find_paths(
+                sd_bus *bus,
+                const char *unit_name,
+                LookupPaths *lp,
+                bool force_client_side,
+                Hashmap **cached_name_map,
+                Hashmap **cached_id_map,
+                char **ret_fragment_path,
+                char ***ret_dropin_paths) {
+
+        _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 *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(ret_fragment_path);
+        assert(lp);
+
+        /* 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 *load_state = NULL, *dbus_path = NULL;
+
+                dbus_path = unit_dbus_path_from_name(unit_name);
+                if (!dbus_path)
+                        return log_oom();
+
+                r = sd_bus_get_property_string(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                dbus_path,
+                                "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 (!STR_IN_SET(load_state, "loaded", "bad-setting"))
+                        return -EKEYREJECTED;
+
+                r = sd_bus_get_property_string(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                dbus_path,
+                                "org.freedesktop.systemd1.Unit",
+                                "FragmentPath",
+                                &error,
+                                &path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
+
+                if (ret_dropin_paths) {
+                        r = sd_bus_get_property_strv(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        dbus_path,
+                                        "org.freedesktop.systemd1.Unit",
+                                        "DropInPaths",
+                                        &error,
+                                        &dropins);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
+                }
+        } else {
+                const char *_path;
+                _cleanup_set_free_free_ Set *names = NULL;
+
+                if (!*cached_name_map) {
+                        r = unit_file_build_name_map(lp, NULL, cached_id_map, cached_name_map, NULL);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = unit_file_find_fragment(*cached_id_map, *cached_name_map, unit_name, &_path, &names);
+                if (r < 0)
+                        return r;
+
+                if (_path) {
+                        path = strdup(_path);
+                        if (!path)
+                                return log_oom();
+                }
+
+                if (ret_dropin_paths) {
+                        r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL,
+                                                        ".d", ".conf",
+                                                        NULL, names, &dropins);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (isempty(path)) {
+                *ret_fragment_path = NULL;
+                r = 0;
+        } else {
+                *ret_fragment_path = TAKE_PTR(path);
+                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);
+
+        return r;
+}
+
+static int unit_find_template_path(
+                const char *unit_name,
+                LookupPaths *lp,
+                char **ret_fragment_path,
+                char **ret_template) {
+
+        _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, &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;
+
+                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, t, ret_fragment_path);
+        if (r < 0)
+                return r;
+
+        if (ret_template)
+                *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
+
+        return r;
+}
+
+int unit_is_masked(sd_bus *bus, LookupPaths *lp, const char *name) {
+        _cleanup_free_ char *load_state = NULL;
+        int r;
+
+        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
+                _cleanup_free_ char *path = NULL;
+
+                /* A template cannot be loaded, but it can be still masked, so
+                 * we need to use a different method. */
+
+                r = unit_file_find_path(lp, name, &path);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return false;
+                return null_or_empty_path(path);
+        }
+
+        r = unit_load_state(bus, name, &load_state);
+        if (r < 0)
+                return r;
+
+        return streq(load_state, "masked");
+}
+
+int unit_exists(LookupPaths *lp, const char *unit) {
+        typedef struct UnitStateInfo {
+                const char *load_state;
+                const char *active_state;
+        } UnitStateInfo;
+
+        static const struct bus_properties_map property_map[] = {
+                { "LoadState",   "s", NULL, offsetof(UnitStateInfo, load_state)   },
+                { "ActiveState", "s", NULL, offsetof(UnitStateInfo, active_state) },
+                {},
+        };
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_free_ char *path = NULL;
+        UnitStateInfo info = {};
+        sd_bus *bus;
+        int r;
+
+        if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
+                return unit_find_template_path(unit, lp, NULL, NULL);
+
+        path = unit_dbus_path_from_name(unit);
+        if (!path)
+                return log_oom();
+
+        r = acquire_bus(BUS_MANAGER, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, 0, &error, &m, &info);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
+
+        return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
+}
+
+
+int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
+        _cleanup_strv_free_ char **with_deps = NULL;
+        char **name;
+
+        assert(bus);
+        assert(ret);
+
+        STRV_FOREACH(name, names) {
+                _cleanup_strv_free_ char **deps = NULL;
+
+                if (strv_extend(&with_deps, *name) < 0)
+                        return log_oom();
+
+                (void) unit_get_dependencies(bus, *name, &deps);
+
+                if (strv_extend_strv(&with_deps, deps, true) < 0)
+                        return log_oom();
+        }
+
+        *ret = TAKE_PTR(with_deps);
+
+        return 0;
+}
+
+int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list) {
+        _cleanup_strv_free_ char **list_with_deps = NULL;
+        int r;
+
+        assert(bus);
+        assert(list);
+
+        if (!arg_with_dependencies)
+                return 0;
+
+        r = append_unit_dependencies(bus, *list, &list_with_deps);
+        if (r < 0)
+                return log_error_errno(r, "Failed to append unit dependencies: %m");
+
+        strv_free(*list);
+        *list = TAKE_PTR(list_with_deps);
+        return 0;
+}
+
+int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
+        _cleanup_strv_free_ char **deps = NULL;
+
+        static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
+                [DEPENDENCY_FORWARD] = {
+                        { "Requires",    "as", NULL, 0 },
+                        { "Requisite",   "as", NULL, 0 },
+                        { "Wants",       "as", NULL, 0 },
+                        { "ConsistsOf",  "as", NULL, 0 },
+                        { "BindsTo",     "as", NULL, 0 },
+                        {}
+                },
+                [DEPENDENCY_REVERSE] = {
+                        { "RequiredBy",  "as", NULL, 0 },
+                        { "RequisiteOf", "as", NULL, 0 },
+                        { "WantedBy",    "as", NULL, 0 },
+                        { "PartOf",      "as", NULL, 0 },
+                        { "BoundBy",     "as", NULL, 0 },
+                        {}
+                },
+                [DEPENDENCY_AFTER] = {
+                        { "After",       "as", NULL, 0 },
+                        {}
+                },
+                [DEPENDENCY_BEFORE] = {
+                        { "Before",      "as", NULL, 0 },
+                        {}
+                },
+        };
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *dbus_path = NULL;
+        int r;
+
+        assert(bus);
+        assert(name);
+        assert(ret);
+
+        dbus_path = unit_dbus_path_from_name(name);
+        if (!dbus_path)
+                return log_oom();
+
+        r = bus_map_all_properties(bus,
+                                   "org.freedesktop.systemd1",
+                                   dbus_path,
+                                   map[arg_dependency],
+                                   BUS_MAP_STRDUP,
+                                   &error,
+                                   NULL,
+                                   &deps);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
+
+        strv_uniq(deps); /* Sometimes a unit might have multiple deps on the other unit,
+                          * but we still want to show it just once. */
+        *ret = TAKE_PTR(deps);
+
+        return 0;
+}
+
+const char* unit_type_suffix(const char *unit) {
+        const char *dot;
+
+        dot = strrchr(unit, '.');
+        if (!dot)
+                return "";
+
+        return dot + 1;
+}
+
+bool output_show_unit(const UnitInfo *u, char **patterns) {
+        assert(u);
+
+        if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
+                return false;
+
+        if (arg_types && !strv_find(arg_types, unit_type_suffix(u->id)))
+                return false;
+
+        if (arg_all)
+                return true;
+
+        /* Note that '--all' is not purely a state filter, but also a filter that hides units that "follow"
+         * other units (which is used for device units that appear under different names). */
+        if (!isempty(u->following))
+                return false;
+
+        if (!strv_isempty(arg_states))
+                return true;
+
+        /* By default show all units except the ones in inactive state and with no pending job */
+        if (u->job_id > 0)
+                return true;
+
+        if (streq(u->active_state, "inactive"))
+                return false;
+
+        return true;
+}
+
+bool install_client_side(void) {
+        /* Decides when to execute enable/disable/... operations client-side rather than server-side. */
+
+        if (running_in_chroot_or_offline())
+                return true;
+
+        if (sd_booted() <= 0)
+                return true;
+
+        if (!isempty(arg_root))
+                return true;
+
+        if (arg_scope == UNIT_FILE_GLOBAL)
+                return true;
+
+        /* Unsupported environment variable, mostly for debugging purposes */
+        if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
+                return true;
+
+        return false;
+}
+
+int output_table(Table *table) {
+        int r;
+
+        assert(table);
+
+        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 table_log_print_error(r);
+
+        return 0;
+}
+
+bool show_preset_for_state(UnitFileState state) {
+        /* Don't show preset state in those unit file states, it'll only confuse users. */
+        return !IN_SET(state,
+                       UNIT_FILE_ALIAS,
+                       UNIT_FILE_STATIC,
+                       UNIT_FILE_GENERATED,
+                       UNIT_FILE_TRANSIENT);
+}
+
+UnitFileFlags unit_file_flags_from_args(void) {
+        return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
+               (arg_force   ? UNIT_FILE_FORCE   : 0);
+}
+
+int mangle_names(const char *operation, char **original_names, char ***ret_mangled_names) {
+        _cleanup_strv_free_ char **l = NULL;
+        char **i, **name;
+        int r;
+
+        assert(ret_mangled_names);
+
+        l = i = new(char*, strv_length(original_names) + 1);
+        if (!l)
+                return log_oom();
+
+        STRV_FOREACH(name, original_names) {
+
+                /* When enabling units qualified path names are OK, too, hence allow them explicitly. */
+
+                if (is_path(*name)) {
+                        *i = strdup(*name);
+                        if (!*i)
+                                return log_oom();
+                } else {
+                        r = unit_name_mangle_with_suffix(*name, operation,
+                                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                                         ".service", i);
+                        if (r < 0) {
+                                *i = NULL;
+                                return log_error_errno(r, "Failed to mangle unit name: %m");
+                        }
+                }
+
+                i++;
+        }
+
+        *i = NULL;
+        *ret_mangled_names = TAKE_PTR(l);
+
+        return 0;
+}
+
+int halt_now(enum action a) {
+        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
+         * to be synced explicitly in advance. */
+        if (!arg_no_sync && !arg_dry_run)
+                (void) sync();
+
+        /* Make sure C-A-D is handled by the kernel from this point on... */
+        if (!arg_dry_run)
+                (void) reboot(RB_ENABLE_CAD);
+
+        switch (a) {
+
+        case ACTION_HALT:
+                if (!arg_quiet)
+                        log_info("Halting.");
+                if (arg_dry_run)
+                        return 0;
+                (void) reboot(RB_HALT_SYSTEM);
+                return -errno;
+
+        case ACTION_POWEROFF:
+                if (!arg_quiet)
+                        log_info("Powering off.");
+                if (arg_dry_run)
+                        return 0;
+                (void) reboot(RB_POWER_OFF);
+                return -errno;
+
+        case ACTION_KEXEC:
+        case ACTION_REBOOT:
+                return reboot_with_parameter(REBOOT_FALLBACK |
+                                             (arg_quiet ? 0 : REBOOT_LOG) |
+                                             (arg_dry_run ? REBOOT_DRY_RUN : 0));
+
+        default:
+                assert_not_reached("Unknown action.");
+        }
+}
diff --git a/src/systemctl/systemctl-util.h b/src/systemctl/systemctl-util.h
new file mode 100644 (file)
index 0000000..3693f1d
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+
+#include "bus-unit-util.h"
+#include "format-table.h"
+#include "systemctl.h"
+
+typedef enum BusFocus {
+        BUS_FULL,      /* The full bus indicated via --system or --user */
+        BUS_MANAGER,   /* The manager itself, possibly directly, possibly via the bus */
+        _BUS_FOCUS_MAX
+} BusFocus;
+
+int acquire_bus(BusFocus focus, sd_bus **ret);
+void release_busses(void);
+
+void ask_password_agent_open_maybe(void);
+void polkit_agent_open_maybe(void);
+
+int translate_bus_error_to_exit_status(int r, const sd_bus_error *error);
+
+int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *ret_active_state);
+int get_unit_list(sd_bus *bus, const char *machine, char **patterns, UnitInfo **unit_infos, int c, sd_bus_message **ret_reply);
+int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded);
+
+int check_triggering_units(sd_bus *bus, const char *unit);
+
+int need_daemon_reload(sd_bus *bus, const char *unit);
+
+void warn_unit_file_changed(const char *unit);
+
+int append_unit_dependencies(sd_bus *bus, char **names, char ***ret);
+int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list);
+
+int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path);
+int unit_find_paths(sd_bus *bus, const char *unit_name, LookupPaths *lp, bool force_client_side, Hashmap **cached_id_map, Hashmap **cached_name_map, char **ret_fragment_path, char ***ret_dropin_paths);
+
+int unit_is_masked(sd_bus *bus, LookupPaths *lp, const char *name);
+int unit_exists(LookupPaths *lp, const char *unit);
+
+int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret);
+
+const char* unit_type_suffix(const char *unit);
+bool output_show_unit(const UnitInfo *u, char **patterns);
+
+bool install_client_side(void);
+
+int output_table(Table *table);
+
+bool show_preset_for_state(UnitFileState state);
+
+int mangle_names(const char *operation, char **original_names, char ***ret_mangled_names);
+
+UnitFileFlags unit_file_flags_from_args(void);
+
+int halt_now(enum action a);
index 115983f98bbdc56045f401dda98860490a85c6f1..075159ea57e50bd1bf7eb841dc6b0d8f19cb618b 100644 (file)
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <errno.h>
-#include <fcntl.h>
 #include <getopt.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/mount.h>
-#include <sys/prctl.h>
-#include <sys/reboot.h>
+#include <locale.h>
 #include <unistd.h>
 
-#include "sd-bus.h"
 #include "sd-daemon.h"
-#include "sd-event.h"
-#include "sd-login.h"
-
-#include "alloc-util.h"
-#include "bootspec.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-locator.h"
-#include "bus-map-properties.h"
-#include "bus-message.h"
-#include "bus-print-properties.h"
-#include "bus-unit-procs.h"
-#include "bus-unit-util.h"
-#include "bus-wait-for-jobs.h"
-#include "bus-wait-for-units.h"
-#include "cgroup-show.h"
-#include "cgroup-util.h"
-#include "copy.h"
-#include "cpu-set-util.h"
-#include "dirent-util.h"
-#include "dropin.h"
-#include "efi-loader.h"
-#include "efivars.h"
-#include "env-util.h"
-#include "escape.h"
-#include "exec-util.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "format-table.h"
-#include "format-util.h"
-#include "fs-util.h"
-#include "glob-util.h"
-#include "hexdecoct.h"
-#include "hostname-util.h"
-#include "in-addr-util.h"
-#include "initreq.h"
-#include "install.h"
-#include "io-util.h"
-#include "journal-util.h"
-#include "list.h"
-#include "locale-util.h"
-#include "log.h"
-#include "logs-show.h"
-#include "macro.h"
-#include "main-func.h"
-#include "memory-util.h"
-#include "mkdir.h"
-#include "numa-util.h"
-#include "pager.h"
-#include "parse-util.h"
-#include "path-lookup.h"
-#include "path-util.h"
-#include "pretty-print.h"
-#include "proc-cmdline.h"
-#include "process-util.h"
-#include "reboot-util.h"
-#include "rlimit-util.h"
-#include "set.h"
-#include "sigbus.h"
-#include "signal-util.h"
-#include "socket-util.h"
-#include "sort-util.h"
-#include "spawn-ask-password-agent.h"
-#include "spawn-polkit-agent.h"
-#include "special.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "strv.h"
-#include "syslog-util.h"
-#include "sysv-compat.h"
-#include "terminal-util.h"
-#include "tmpfile-util.h"
-#include "unit-def.h"
-#include "unit-file.h"
-#include "unit-name.h"
-#include "user-util.h"
-#include "utf8.h"
-#include "utmp-wtmp.h"
-#include "verbs.h"
-#include "virt.h"
-
-static char **arg_types = NULL;
-static char **arg_states = NULL;
-static char **arg_properties = NULL;
-static bool arg_all = false;
-static enum dependency {
-        DEPENDENCY_FORWARD,
-        DEPENDENCY_REVERSE,
-        DEPENDENCY_AFTER,
-        DEPENDENCY_BEFORE,
-        _DEPENDENCY_MAX
-} arg_dependency = DEPENDENCY_FORWARD;
-static const char *arg_job_mode = "replace";
-static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
-static bool arg_wait = false;
-static bool arg_no_block = false;
-static bool arg_no_legend = false;
-static PagerFlags arg_pager_flags = 0;
-static bool arg_no_wtmp = false;
-static bool arg_no_sync = false;
-static bool arg_no_wall = false;
-static bool arg_no_reload = false;
-static bool arg_value = false;
-static bool arg_show_types = false;
-static bool arg_ignore_inhibitors = false;
-static bool arg_dry_run = false;
-static bool arg_quiet = false;
-static bool arg_full = false;
-static bool arg_recursive = false;
-static bool arg_with_dependencies = false;
-static bool arg_show_transaction = false;
-static int arg_force = 0;
-static bool arg_ask_password = false;
-static bool arg_runtime = false;
-static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
-static char **arg_wall = NULL;
-static const char *arg_kill_who = NULL;
-static int arg_signal = SIGTERM;
-static char *arg_root = NULL;
-static usec_t arg_when = 0;
-static const char *arg_reboot_argument = NULL;
-static enum action {
-        ACTION_SYSTEMCTL,
-        ACTION_HALT,
-        ACTION_POWEROFF,
-        ACTION_REBOOT,
-        ACTION_KEXEC,
-        ACTION_EXIT,
-        ACTION_SUSPEND,
-        ACTION_HIBERNATE,
-        ACTION_HYBRID_SLEEP,
-        ACTION_SUSPEND_THEN_HIBERNATE,
-        ACTION_RUNLEVEL2,
-        ACTION_RUNLEVEL3,
-        ACTION_RUNLEVEL4,
-        ACTION_RUNLEVEL5,
-        ACTION_RESCUE,
-        ACTION_EMERGENCY,
-        ACTION_DEFAULT,
-        ACTION_RELOAD,
-        ACTION_REEXEC,
-        ACTION_RUNLEVEL,
-        ACTION_CANCEL_SHUTDOWN,
-        _ACTION_MAX,
-        _ACTION_INVALID = -1
-} arg_action = ACTION_SYSTEMCTL;
-static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static const char *arg_host = NULL;
-static unsigned arg_lines = 10;
-static OutputMode arg_output = OUTPUT_SHORT;
-static bool arg_plain = false;
-static bool arg_firmware_setup = false;
-static usec_t arg_boot_loader_menu = USEC_INFINITY;
-static const char *arg_boot_loader_entry = NULL;
-static bool arg_now = false;
-static bool arg_jobs_before = false;
-static bool arg_jobs_after = false;
-static char **arg_clean_what = NULL;
-static TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
-
-/* This is a global cache that will be constructed on first use. */
-static Hashmap *cached_id_map = NULL;
-static Hashmap *cached_name_map = NULL;
-
-STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(cached_id_map, hashmap_freep);
-STATIC_DESTRUCTOR_REGISTER(cached_name_map, hashmap_freep);
-
-static int daemon_reload(int argc, char *argv[], void* userdata);
-static int trivial_method(int argc, char *argv[], void *userdata);
-static int halt_now(enum action a);
-static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state);
-
-static bool original_stdout_is_tty;
-
-typedef enum BusFocus {
-        BUS_FULL,      /* The full bus indicated via --system or --user */
-        BUS_MANAGER,   /* The manager itself, possibly directly, possibly via the bus */
-        _BUS_FOCUS_MAX
-} BusFocus;
-
-static sd_bus *buses[_BUS_FOCUS_MAX] = {};
-
-static UnitFileFlags args_to_flags(void) {
-        return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
-               (arg_force   ? UNIT_FILE_FORCE   : 0);
-}
-
-static int acquire_bus(BusFocus focus, sd_bus **ret) {
-        int r;
-
-        assert(focus < _BUS_FOCUS_MAX);
-        assert(ret);
-
-        /* We only go directly to the manager, if we are using a local transport */
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                focus = BUS_FULL;
-
-        if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
-                focus = BUS_FULL;
-
-        if (!buses[focus]) {
-                bool user;
-
-                user = arg_scope != UNIT_FILE_SYSTEM;
-
-                if (focus == BUS_MANAGER)
-                        r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
-                else
-                        r = bus_connect_transport(arg_transport, arg_host, user, &buses[focus]);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to connect to bus: %m");
-
-                (void) sd_bus_set_allow_interactive_authorization(buses[focus], arg_ask_password);
-        }
-
-        *ret = buses[focus];
-        return 0;
-}
-
-static void release_busses(void) {
-        BusFocus w;
-
-        for (w = 0; w < _BUS_FOCUS_MAX; w++)
-                buses[w] = sd_bus_flush_close_unref(buses[w]);
-}
-
-static void ask_password_agent_open_maybe(void) {
-        /* Open the password agent as a child process if necessary */
-
-        if (arg_dry_run)
-                return;
-
-        if (arg_scope != UNIT_FILE_SYSTEM)
-                return;
-
-        ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
-}
-
-static void polkit_agent_open_maybe(void) {
-        /* Open the polkit agent as a child process if necessary */
-
-        if (arg_scope != UNIT_FILE_SYSTEM)
-                return;
-
-        polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
-}
-
-static OutputFlags get_output_flags(void) {
-        return
-                arg_all * OUTPUT_SHOW_ALL |
-                (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
-                colors_enabled() * OUTPUT_COLOR |
-                !arg_quiet * OUTPUT_WARN_CUTOFF;
-}
-
-static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
-        assert(error);
-
-        if (!sd_bus_error_is_set(error))
-                return r;
-
-        if (sd_bus_error_has_names(error, SD_BUS_ERROR_ACCESS_DENIED,
-                                          BUS_ERROR_ONLY_BY_DEPENDENCY,
-                                          BUS_ERROR_NO_ISOLATION,
-                                          BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
-                return EXIT_NOPERMISSION;
-
-        if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
-                return EXIT_NOTINSTALLED;
-
-        if (sd_bus_error_has_names(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
-                                          SD_BUS_ERROR_NOT_SUPPORTED))
-                return EXIT_NOTIMPLEMENTED;
-
-        if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
-                return EXIT_NOTCONFIGURED;
-
-        if (r != 0)
-                return r;
-
-        return EXIT_FAILURE;
-}
-
-static bool install_client_side(void) {
-        /* Decides when to execute enable/disable/... operations
-         * client-side rather than server-side. */
-
-        if (running_in_chroot_or_offline())
-                return true;
-
-        if (sd_booted() <= 0)
-                return true;
-
-        if (!isempty(arg_root))
-                return true;
-
-        if (arg_scope == UNIT_FILE_GLOBAL)
-                return true;
-
-        /* Unsupported environment variable, mostly for debugging purposes */
-        if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
-                return true;
-
-        return false;
-}
-
-static int compare_unit_info(const UnitInfo *a, const UnitInfo *b) {
-        int r;
-
-        /* First, order by machine */
-        r = strcasecmp_ptr(a->machine, b->machine);
-        if (r != 0)
-                return r;
-
-        /* Second, order by unit type */
-        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
-        if (r != 0)
-                return r;
-
-        /* Third, order by name */
-        return strcasecmp(a->id, b->id);
-}
-
-static const char* unit_type_suffix(const char *name) {
-        const char *dot;
-
-        dot = strrchr(name, '.');
-        if (!dot)
-                return "";
-
-        return dot + 1;
-}
-
-static bool output_show_unit(const UnitInfo *u, char **patterns) {
-        assert(u);
-
-        if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
-                return false;
-
-        if (arg_types && !strv_find(arg_types, unit_type_suffix(u->id)))
-                return false;
-
-        if (arg_all)
-                return true;
-
-        /* Note that '--all' is not purely a state filter, but also a
-         * filter that hides units that "follow" other units (which is
-         * used for device units that appear under different names). */
-        if (!isempty(u->following))
-                return false;
-
-        if (!strv_isempty(arg_states))
-                return true;
-
-        /* By default show all units except the ones in inactive
-         * state and with no pending job */
-        if (u->job_id > 0)
-                return true;
-
-        if (streq(u->active_state, "inactive"))
-                return false;
-
-        return true;
-}
-
-static int output_table(Table *table) {
-        int r;
-
-        assert(table);
-
-        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 table_log_print_error(r);
-
-        return 0;
-}
-
-static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        int r;
-
-        table = table_new("", "unit", "load", "active", "sub", "job", "description");
-        if (!table)
-                return log_oom();
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_plain) {
-                /* Hide the 'glyph' column when --plain is requested */
-                r = table_hide_column_from_display(table, 0);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to hide column: %m");
-        }
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        int job_count = 0;
-        for (const UnitInfo *u = unit_infos; unit_infos && u < unit_infos + c; u++) {
-                _cleanup_free_ char *j = NULL;
-                const char *on_underline = "", *on_loaded = "", *on_active = "";
-                const char *on_circle = "", *id;
-                bool circle = false, underline = false;
-
-                if (u + 1 < unit_infos + c &&
-                    !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
-                        on_underline = ansi_underline();
-                        underline = true;
-                }
-
-                if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
-                        on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
-                        circle = true;
-                        on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                } else if (streq(u->active_state, "failed") && !arg_plain) {
-                        on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                        circle = true;
-                        on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                } else {
-                        on_circle = on_underline;
-                        on_active = on_underline;
-                        on_loaded = on_underline;
-                }
-
-                if (u->machine) {
-                        j = strjoin(u->machine, ":", u->id);
-                        if (!j)
-                                return log_oom();
-
-                        id = j;
-                } else
-                        id = u->id;
-
-                r = table_add_many(table,
-                                   TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
-                                   TABLE_SET_BOTH_COLORS, on_circle,
-                                   TABLE_STRING, id,
-                                   TABLE_SET_BOTH_COLORS, on_active,
-                                   TABLE_STRING, u->load_state,
-                                   TABLE_SET_BOTH_COLORS, on_loaded,
-                                   TABLE_STRING, u->active_state,
-                                   TABLE_SET_BOTH_COLORS, on_active,
-                                   TABLE_STRING, u->sub_state,
-                                   TABLE_SET_BOTH_COLORS, on_active,
-                                   TABLE_STRING, u->job_id ? u->job_type: "",
-                                   TABLE_SET_BOTH_COLORS, u->job_id ? on_underline : "",
-                                   TABLE_STRING, u->description,
-                                   TABLE_SET_BOTH_COLORS, on_underline);
-                if (r < 0)
-                        return table_log_add_error(r);
-
-                if (u->job_id != 0)
-                        job_count++;
-        }
-
-        if (job_count == 0) {
-                /* There's no data in the JOB column, so let's hide it */
-                r = table_hide_column_from_display(table, 5);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to hide column: %m");
-        }
-
-        r = output_table(table);
-        if (r < 0)
-                return r;
-
-        if (!arg_no_legend) {
-                const char *on, *off;
-                size_t records = table_get_rows(table) - 1;
-
-                if (records > 0) {
-                        puts("\n"
-                             "LOAD   = Reflects whether the unit definition was properly loaded.\n"
-                             "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
-                             "SUB    = The low-level unit activation state, values depend on unit type.");
-                        puts(job_count ? "JOB    = Pending job for the unit.\n" : "");
-                        on = ansi_highlight();
-                        off = ansi_normal();
-                } else {
-                        on = ansi_highlight_red();
-                        off = ansi_normal();
-                }
-
-                if (arg_all || strv_contains(arg_states, "inactive"))
-                        printf("%s%zu loaded units listed.%s\n"
-                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
-                               on, records, off);
-                else if (!arg_states)
-                        printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
-                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
-                               on, records, off);
-                else
-                        printf("%zu loaded units listed.\n", records);
-        }
-
-        return 0;
-}
-
-static int get_unit_list(
-                sd_bus *bus,
-                const char *machine,
-                char **patterns,
-                UnitInfo **unit_infos,
-                int c,
-                sd_bus_message **_reply) {
-
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        size_t size = c;
-        int r;
-        UnitInfo u;
-        bool fallback = false;
-
-        assert(bus);
-        assert(unit_infos);
-        assert(_reply);
-
-        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_message_append_strv(m, arg_states);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_message_append_strv(m, patterns);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0 && (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
-                                                     SD_BUS_ERROR_ACCESS_DENIED))) {
-                /* Fallback to legacy ListUnitsFiltered method */
-                fallback = true;
-                log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
-                m = sd_bus_message_unref(m);
-                sd_bus_error_free(&error);
-
-                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append_strv(m, arg_states);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_call(bus, m, 0, &error, &reply);
-        }
-        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);
-
-        while ((r = bus_parse_unit_info(reply, &u)) > 0) {
-                u.machine = machine;
-
-                if (!output_show_unit(&u, fallback ? patterns : NULL))
-                        continue;
-
-                if (!GREEDY_REALLOC(*unit_infos, size, c+1))
-                        return log_oom();
-
-                (*unit_infos)[c++] = u;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        *_reply = TAKE_PTR(reply);
-
-        return c;
-}
-
-static void message_set_freep(Set **set) {
-        set_free_with_destructor(*set, sd_bus_message_unref);
-}
-
-static int get_unit_list_recursive(
-                sd_bus *bus,
-                char **patterns,
-                UnitInfo **_unit_infos,
-                Set **_replies,
-                char ***_machines) {
-
-        _cleanup_free_ UnitInfo *unit_infos = NULL;
-        _cleanup_(message_set_freep) Set *replies;
-        sd_bus_message *reply;
-        int c, r;
-
-        assert(bus);
-        assert(_replies);
-        assert(_unit_infos);
-        assert(_machines);
-
-        replies = set_new(NULL);
-        if (!replies)
-                return log_oom();
-
-        c = get_unit_list(bus, NULL, patterns, &unit_infos, 0, &reply);
-        if (c < 0)
-                return c;
-
-        r = set_put(replies, reply);
-        if (r < 0) {
-                sd_bus_message_unref(reply);
-                return log_oom();
-        }
-
-        if (arg_recursive) {
-                _cleanup_strv_free_ char **machines = NULL;
-                char **i;
-
-                r = sd_get_machine_names(&machines);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get machine names: %m");
-
-                STRV_FOREACH(i, machines) {
-                        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
-                        int k;
-
-                        r = sd_bus_open_system_machine(&container, *i);
-                        if (r < 0) {
-                                log_warning_errno(r, "Failed to connect to container %s, ignoring: %m", *i);
-                                continue;
-                        }
-
-                        k = get_unit_list(container, *i, patterns, &unit_infos, c, &reply);
-                        if (k < 0)
-                                return k;
-
-                        c = k;
-
-                        r = set_put(replies, reply);
-                        if (r < 0) {
-                                sd_bus_message_unref(reply);
-                                return log_oom();
-                        }
-                }
-
-                *_machines = TAKE_PTR(machines);
-        } else
-                *_machines = NULL;
-
-        *_unit_infos = TAKE_PTR(unit_infos);
-        *_replies = TAKE_PTR(replies);
-
-        return c;
-}
-
-static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
-        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
-        char **name;
-        int r, i;
-
-        assert(bus);
-        assert(ret);
-
-        STRV_FOREACH(name, names) {
-                char *t;
-                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
-
-                r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to mangle name: %m");
-
-                if (string_is_glob(t))
-                        r = strv_consume(&globs, t);
-                else
-                        r = strv_consume(&mangled, t);
-                if (r < 0)
-                        return log_oom();
-        }
-
-        /* Query the manager only if any of the names are a glob, since
-         * this is fairly expensive */
-        bool expanded = !strv_isempty(globs);
-        if (expanded) {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                _cleanup_free_ UnitInfo *unit_infos = NULL;
-                size_t allocated, n;
-
-                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
-                if (r < 0)
-                        return r;
-
-                n = strv_length(mangled);
-                allocated = n + 1;
-
-                for (i = 0; i < r; i++) {
-                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
-                                return log_oom();
-
-                        mangled[n] = strdup(unit_infos[i].id);
-                        if (!mangled[n])
-                                return log_oom();
-
-                        mangled[++n] = NULL;
-                }
-        }
-
-        if (ret_expanded)
-                *ret_expanded = expanded;
-
-        *ret = TAKE_PTR(mangled);
-        return 0;
-}
-
-static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
-        _cleanup_strv_free_ char **deps = NULL;
-
-        static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
-                [DEPENDENCY_FORWARD] = {
-                        { "Requires",    "as", NULL, 0 },
-                        { "Requisite",   "as", NULL, 0 },
-                        { "Wants",       "as", NULL, 0 },
-                        { "ConsistsOf",  "as", NULL, 0 },
-                        { "BindsTo",     "as", NULL, 0 },
-                        {}
-                },
-                [DEPENDENCY_REVERSE] = {
-                        { "RequiredBy",  "as", NULL, 0 },
-                        { "RequisiteOf", "as", NULL, 0 },
-                        { "WantedBy",    "as", NULL, 0 },
-                        { "PartOf",      "as", NULL, 0 },
-                        { "BoundBy",     "as", NULL, 0 },
-                        {}
-                },
-                [DEPENDENCY_AFTER] = {
-                        { "After",       "as", NULL, 0 },
-                        {}
-                },
-                [DEPENDENCY_BEFORE] = {
-                        { "Before",      "as", NULL, 0 },
-                        {}
-                },
-        };
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *dbus_path = NULL;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(ret);
-
-        dbus_path = unit_dbus_path_from_name(name);
-        if (!dbus_path)
-                return log_oom();
-
-        r = bus_map_all_properties(bus,
-                                   "org.freedesktop.systemd1",
-                                   dbus_path,
-                                   map[arg_dependency],
-                                   BUS_MAP_STRDUP,
-                                   &error,
-                                   NULL,
-                                   &deps);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
-
-        strv_uniq(deps); /* Sometimes a unit might have multiple deps on the other unit,
-                          * but we still want to show it just once. */
-        *ret = TAKE_PTR(deps);
-
-        return 0;
-}
-
-static int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
-        _cleanup_strv_free_ char **with_deps = NULL;
-        char **name;
-
-        assert(bus);
-        assert(ret);
-
-        STRV_FOREACH(name, names) {
-                _cleanup_strv_free_ char **deps = NULL;
-
-                if (strv_extend(&with_deps, *name) < 0)
-                        return log_oom();
-
-                (void) list_dependencies_get_dependencies(bus, *name, &deps);
-
-                if (strv_extend_strv(&with_deps, deps, true) < 0)
-                        return log_oom();
-        }
-
-        *ret = TAKE_PTR(with_deps);
-
-        return 0;
-}
-
-static int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list) {
-        assert(bus);
-        assert(list);
-
-        if (arg_with_dependencies) {
-                int r;
-                _cleanup_strv_free_ char **list_with_deps = NULL;
-
-                r = append_unit_dependencies(bus, *list, &list_with_deps);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to append unit dependencies: %m");
-
-                strv_free(*list);
-                *list = TAKE_PTR(list_with_deps);
-        }
-
-        return 0;
-}
-
-static int list_units(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ UnitInfo *unit_infos = NULL;
-        _cleanup_(message_set_freep) Set *replies = NULL;
-        _cleanup_strv_free_ char **machines = NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        if (arg_with_dependencies) {
-                _cleanup_strv_free_ char **names = NULL;
-
-                r = append_unit_dependencies(bus, strv_skip(argv, 1), &names);
-                if (r < 0)
-                        return r;
-
-                r = get_unit_list_recursive(bus, names, &unit_infos, &replies, &machines);
-                if (r < 0)
-                        return r;
-        } else {
-                r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
-                if (r < 0)
-                        return r;
-        }
-
-        typesafe_qsort(unit_infos, r, compare_unit_info);
-        return output_units_list(unit_infos, r);
-}
-
-static int get_triggered_units(
-                sd_bus *bus,
-                const char* path,
-                char*** ret) {
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(ret);
-
-        r = sd_bus_get_property_strv(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Unit",
-                        "Triggers",
-                        &error,
-                        ret);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
-
-        return 0;
-}
-
-static int get_listening(
-                sd_bus *bus,
-                const char* unit_path,
-                char*** listening) {
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *type, *path;
-        int r, n = 0;
-
-        r = sd_bus_get_property(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        unit_path,
-                        "org.freedesktop.systemd1.Socket",
-                        "Listen",
-                        &error,
-                        &reply,
-                        "a(ss)");
-        if (r < 0)
-                return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
-
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
-
-                r = strv_extend(listening, type);
-                if (r < 0)
-                        return log_oom();
-
-                r = strv_extend(listening, path);
-                if (r < 0)
-                        return log_oom();
-
-                n++;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return n;
-}
-
-struct socket_info {
-        const char *machine;
-        const char* id;
-
-        char* type;
-        char* path;
-
-        /* Note: triggered is a list here, although it almost certainly
-         * will always be one unit. Nevertheless, dbus API allows for multiple
-         * values, so let's follow that. */
-        char** triggered;
-
-        /* The strv above is shared. free is set only in the first one. */
-        bool own_triggered;
-};
-
-static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
-        int r;
-
-        assert(a);
-        assert(b);
-
-        r = strcasecmp_ptr(a->machine, b->machine);
-        if (r != 0)
-                return r;
-
-        r = strcmp(a->path, b->path);
-        if (r != 0)
-                return r;
-
-        return strcmp(a->type, b->type);
-}
-
-static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        struct socket_info *s;
-        const char *on, *off;
-        int r;
-
-        table = table_new("listen", "type", "unit", "activates");
-        if (!table)
-                return log_oom();
-
-        if (!arg_show_types) {
-                /* Hide the second (TYPE) column */
-                r = table_set_display(table, (size_t) 0, (size_t) 2, (size_t) 3, (size_t) -1);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to set columns to display: %m");
-        }
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        if (cs) {
-                for (s = socket_infos; s < socket_infos + cs; s++) {
-                        _cleanup_free_ char *j = NULL;
-                        const char *path;
-
-                        if (s->machine) {
-                                j = strjoin(s->machine, ":", s->path);
-                                if (!j)
-                                        return log_oom();
-                                path = j;
-                        } else
-                                path = s->path;
-
-                        r = table_add_many(table,
-                                           TABLE_STRING, path,
-                                           TABLE_STRING, s->type,
-                                           TABLE_STRING, s->id);
-                        if (r < 0)
-                                return table_log_add_error(r);
-
-                        if (strv_isempty(s->triggered))
-                                r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
-                        else if (strv_length(s->triggered) == 1)
-                                r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]);
-                        else
-                                /* This should never happen, currently our socket units can only trigger a
-                                 * single unit. But let's handle this anyway, who knows what the future
-                                 * brings? */
-                                r = table_add_cell(table, NULL, TABLE_STRV, s->triggered);
-                        if (r < 0)
-                                return table_log_add_error(r);
-
-                }
-
-                on = ansi_highlight();
-                off = ansi_normal();
-        } else {
-                on = ansi_highlight_red();
-                off = ansi_normal();
-        }
-
-        r = output_table(table);
-        if (r < 0)
-                return r;
-
-        if (!arg_no_legend) {
-                printf("\n%s%u sockets listed.%s\n", on, cs, off);
-                if (!arg_all)
-                        printf("Pass --all to see loaded but inactive sockets, too.\n");
-        }
-
-        return 0;
-}
-
-static int list_sockets(int argc, char *argv[], void *userdata) {
-        _cleanup_(message_set_freep) Set *replies = NULL;
-        _cleanup_strv_free_ char **machines = NULL;
-        _cleanup_strv_free_ char **sockets_with_suffix = NULL;
-        _cleanup_free_ UnitInfo *unit_infos = NULL;
-        _cleanup_free_ struct socket_info *socket_infos = NULL;
-        const UnitInfo *u;
-        struct socket_info *s;
-        unsigned cs = 0;
-        size_t size = 0;
-        int r, n;
-        sd_bus *bus;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        r = expand_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix, NULL);
-        if (r < 0)
-                return r;
-
-        if (argc == 1 || sockets_with_suffix) {
-                n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines);
-                if (n < 0)
-                        return n;
-
-                for (u = unit_infos; u < unit_infos + n; u++) {
-                        _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
-                        int i, c;
-
-                        if (!endswith(u->id, ".socket"))
-                                continue;
-
-                        r = get_triggered_units(bus, u->unit_path, &triggered);
-                        if (r < 0)
-                                goto cleanup;
-
-                        c = get_listening(bus, u->unit_path, &listening);
-                        if (c < 0) {
-                                r = c;
-                                goto cleanup;
-                        }
-
-                        if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
-                                r = log_oom();
-                                goto cleanup;
-                        }
-
-                        for (i = 0; i < c; i++)
-                                socket_infos[cs + i] = (struct socket_info) {
-                                        .machine = u->machine,
-                                        .id = u->id,
-                                        .type = listening[i*2],
-                                        .path = listening[i*2 + 1],
-                                        .triggered = triggered,
-                                        .own_triggered = i==0,
-                                };
-
-                        /* from this point on we will cleanup those socket_infos */
-                        cs += c;
-                        free(listening);
-                        listening = triggered = NULL; /* avoid cleanup */
-                }
-
-                typesafe_qsort(socket_infos, cs, socket_info_compare);
-        }
-
-        output_sockets_list(socket_infos, cs);
-
- cleanup:
-        assert(cs == 0 || socket_infos);
-        for (s = socket_infos; s < socket_infos + cs; s++) {
-                free(s->type);
-                free(s->path);
-                if (s->own_triggered)
-                        strv_free(s->triggered);
-        }
-
-        return r;
-}
-
-static int get_next_elapse(
-                sd_bus *bus,
-                const char *path,
-                dual_timestamp *next) {
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        dual_timestamp t;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(next);
-
-        r = sd_bus_get_property_trivial(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Timer",
-                        "NextElapseUSecMonotonic",
-                        &error,
-                        't',
-                        &t.monotonic);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
-
-        r = sd_bus_get_property_trivial(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Timer",
-                        "NextElapseUSecRealtime",
-                        &error,
-                        't',
-                        &t.realtime);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
-
-        *next = t;
-        return 0;
-}
-
-static int get_last_trigger(
-                sd_bus *bus,
-                const char *path,
-                usec_t *last) {
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(last);
-
-        r = sd_bus_get_property_trivial(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Timer",
-                        "LastTriggerUSec",
-                        &error,
-                        't',
-                        last);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
-
-        return 0;
-}
-
-struct timer_info {
-        const char* machine;
-        const char* id;
-        usec_t next_elapse;
-        usec_t last_trigger;
-        char** triggered;
-};
-
-static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
-        int r;
-
-        assert(a);
-        assert(b);
-
-        r = strcasecmp_ptr(a->machine, b->machine);
-        if (r != 0)
-                return r;
-
-        r = CMP(a->next_elapse, b->next_elapse);
-        if (r != 0)
-                return r;
-
-        return strcmp(a->id, b->id);
-}
-
-static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        struct timer_info *t;
-        const char *on, *off;
-        int r;
-
-        assert(timer_infos || n == 0);
-
-        table = table_new("next", "left", "last", "passed", "unit", "activates");
-        if (!table)
-                return log_oom();
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        if (n > 0) {
-                for (t = timer_infos; t < timer_infos + n; t++) {
-                        _cleanup_free_ char *j = NULL, *activates = NULL;
-                        const char *unit;
-
-                        if (t->machine) {
-                                j = strjoin(t->machine, ":", t->id);
-                                if (!j)
-                                        return log_oom();
-                                unit = j;
-                        } else
-                                unit = t->id;
-
-                        activates = strv_join(t->triggered, ", ");
-                        if (!activates)
-                                return log_oom();
-
-                        r = table_add_many(table,
-                                           TABLE_TIMESTAMP, t->next_elapse,
-                                           TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
-                                           TABLE_TIMESTAMP, t->last_trigger,
-                                           TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
-                                           TABLE_STRING, unit,
-                                           TABLE_STRING, activates);
-                        if (r < 0)
-                                return table_log_add_error(r);
-                }
-
-                on = ansi_highlight();
-                off = ansi_normal();
-        } else {
-                on = ansi_highlight_red();
-                off = ansi_normal();
-        }
-
-        r = output_table(table);
-        if (r < 0)
-                return r;
-
-        if (!arg_no_legend) {
-                printf("\n%s%u timers listed.%s\n", on, n, off);
-                if (!arg_all)
-                        printf("Pass --all to see loaded but inactive timers, too.\n");
-        }
-
-        return 0;
-}
-
-static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
-        usec_t next_elapse;
-
-        assert(nw);
-        assert(next);
-
-        if (timestamp_is_set(next->monotonic)) {
-                usec_t converted;
-
-                if (next->monotonic > nw->monotonic)
-                        converted = nw->realtime + (next->monotonic - nw->monotonic);
-                else
-                        converted = nw->realtime - (nw->monotonic - next->monotonic);
-
-                if (timestamp_is_set(next->realtime))
-                        next_elapse = MIN(converted, next->realtime);
-                else
-                        next_elapse = converted;
-
-        } else
-                next_elapse = next->realtime;
-
-        return next_elapse;
-}
-
-static int list_timers(int argc, char *argv[], void *userdata) {
-        _cleanup_(message_set_freep) Set *replies = NULL;
-        _cleanup_strv_free_ char **machines = NULL;
-        _cleanup_strv_free_ char **timers_with_suffix = NULL;
-        _cleanup_free_ struct timer_info *timer_infos = NULL;
-        _cleanup_free_ UnitInfo *unit_infos = NULL;
-        struct timer_info *t;
-        const UnitInfo *u;
-        size_t size = 0;
-        int n, c = 0;
-        dual_timestamp nw;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        r = expand_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix, NULL);
-        if (r < 0)
-                return r;
-
-        if (argc == 1 || timers_with_suffix) {
-                n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines);
-                if (n < 0)
-                        return n;
-
-                dual_timestamp_get(&nw);
-
-                for (u = unit_infos; u < unit_infos + n; u++) {
-                        _cleanup_strv_free_ char **triggered = NULL;
-                        dual_timestamp next = DUAL_TIMESTAMP_NULL;
-                        usec_t m, last = 0;
-
-                        if (!endswith(u->id, ".timer"))
-                                continue;
-
-                        r = get_triggered_units(bus, u->unit_path, &triggered);
-                        if (r < 0)
-                                goto cleanup;
-
-                        r = get_next_elapse(bus, u->unit_path, &next);
-                        if (r < 0)
-                                goto cleanup;
-
-                        get_last_trigger(bus, u->unit_path, &last);
-
-                        if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
-                                r = log_oom();
-                                goto cleanup;
-                        }
-
-                        m = calc_next_elapse(&nw, &next);
-
-                        timer_infos[c++] = (struct timer_info) {
-                                .machine = u->machine,
-                                .id = u->id,
-                                .next_elapse = m,
-                                .last_trigger = last,
-                                .triggered = TAKE_PTR(triggered),
-                        };
-                }
-
-                typesafe_qsort(timer_infos, c, timer_info_compare);
-        }
-
-        output_timers_list(timer_infos, c);
-
- cleanup:
-        for (t = timer_infos; t < timer_infos + c; t++)
-                strv_free(t->triggered);
-
-        return r;
-}
-
-static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
-        const char *d1, *d2;
-
-        d1 = strrchr(a->path, '.');
-        d2 = strrchr(b->path, '.');
-
-        if (d1 && d2) {
-                int r;
-
-                r = strcasecmp(d1, d2);
-                if (r != 0)
-                        return r;
-        }
-
-        return strcasecmp(basename(a->path), basename(b->path));
-}
-
-static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
-        assert(u);
-
-        if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
-                return false;
-
-        if (!strv_isempty(arg_types)) {
-                const char *dot;
-
-                dot = strrchr(u->path, '.');
-                if (!dot)
-                        return false;
-
-                if (!strv_find(arg_types, dot+1))
-                        return false;
-        }
-
-        if (!strv_isempty(states) &&
-            !strv_find(states, unit_file_state_to_string(u->state)))
-                return false;
-
-        return true;
-}
-
-static bool show_preset_for_state(UnitFileState state) {
-        /* Don't show preset state in those unit file states, it'll only confuse users. */
-        return !IN_SET(state,
-                       UNIT_FILE_ALIAS,
-                       UNIT_FILE_STATIC,
-                       UNIT_FILE_GENERATED,
-                       UNIT_FILE_TRANSIENT);
-}
-
-static int output_unit_file_list(const UnitFileList *units, unsigned c) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
-        int r;
-
-        table = table_new("unit file", "state", "vendor preset");
-        if (!table)
-                return log_oom();
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        for (const UnitFileList *u = units; u < units + c; u++) {
-                const char *on_underline = NULL, *on_unit_color = NULL, *id;
-                bool underline;
-
-                underline = u + 1 < units + c &&
-                        !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
-
-                if (underline)
-                        on_underline = ansi_underline();
-
-                if (IN_SET(u->state,
-                           UNIT_FILE_MASKED,
-                           UNIT_FILE_MASKED_RUNTIME,
-                           UNIT_FILE_DISABLED,
-                           UNIT_FILE_BAD))
-                        on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                else if (IN_SET(u->state,
-                                UNIT_FILE_ENABLED,
-                                UNIT_FILE_ALIAS))
-                        on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
-                else
-                        on_unit_color = on_underline;
-
-                id = basename(u->path);
-
-                r = table_add_many(table,
-                                   TABLE_STRING, id,
-                                   TABLE_SET_BOTH_COLORS, strempty(on_underline),
-                                   TABLE_STRING, unit_file_state_to_string(u->state),
-                                   TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
-                if (r < 0)
-                        return table_log_add_error(r);
-
-                if (show_preset_for_state(u->state)) {
-                        const char *unit_preset_str, *on_preset_color;
-
-                        r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
-                        if (r < 0) {
-                                unit_preset_str = "n/a";
-                                on_preset_color = underline ? on_underline : ansi_normal();
-                        } else if (r == 0) {
-                                unit_preset_str = "disabled";
-                                on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                        } else {
-                                unit_preset_str = "enabled";
-                                on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
-                        }
-
-                        r = table_add_many(table,
-                                           TABLE_STRING, unit_preset_str,
-                                           TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
-                } else
-                        r = table_add_many(table,
-                                           TABLE_EMPTY,
-                                           TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
-                if (r < 0)
-                        return table_log_add_error(r);
-        }
-
-        r = output_table(table);
-        if (r < 0)
-                return r;
-
-        if (!arg_no_legend)
-                printf("\n%u unit files listed.\n", c);
-
-        return 0;
-}
-
-static int list_unit_files(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_free_ UnitFileList *units = NULL;
-        UnitFileList *unit;
-        size_t size = 0;
-        unsigned c = 0;
-        const char *state;
-        char *path;
-        int r;
-        bool fallback = false;
-
-        if (install_client_side()) {
-                Hashmap *h;
-                UnitFileList *u;
-                unsigned n_units;
-
-                h = hashmap_new(&string_hash_ops);
-                if (!h)
-                        return log_oom();
-
-                r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
-                if (r < 0) {
-                        unit_file_list_free(h);
-                        return log_error_errno(r, "Failed to get unit file list: %m");
-                }
-
-                n_units = hashmap_size(h);
-
-                units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
-                if (!units) {
-                        unit_file_list_free(h);
-                        return log_oom();
-                }
-
-                HASHMAP_FOREACH(u, h) {
-                        if (!output_show_unit_file(u, NULL, NULL))
-                                continue;
-
-                        units[c++] = *u;
-                        free(u);
-                }
-
-                assert(c <= n_units);
-                hashmap_free(h);
-
-                r = 0;
-        } else {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                sd_bus *bus;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append_strv(m, arg_states);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                if (arg_with_dependencies) {
-                        _cleanup_strv_free_ char **names_with_deps = NULL;
-
-                        r = append_unit_dependencies(bus, strv_skip(argv, 1), &names_with_deps);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to append unit dependencies: %m");
-
-                        r = sd_bus_message_append_strv(m, names_with_deps);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                } else {
-                        r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_call(bus, m, 0, &error, &reply);
-                if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
-                        /* Fallback to legacy ListUnitFiles method */
-                        fallback = true;
-                        log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
-                        m = sd_bus_message_unref(m);
-                        sd_bus_error_free(&error);
-
-                        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
-                        if (r < 0)
-                                return bus_log_create_error(r);
-
-                        r = sd_bus_call(bus, m, 0, &error, &reply);
-                }
-                if (r < 0)
-                        return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
-
-                r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
-                while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
-
-                        if (!GREEDY_REALLOC(units, size, c + 1))
-                                return log_oom();
-
-                        units[c] = (struct UnitFileList) {
-                                path,
-                                unit_file_state_from_string(state)
-                        };
-
-                        if (output_show_unit_file(&units[c],
-                            fallback ? arg_states : NULL,
-                            fallback ? strv_skip(argv, 1) : NULL))
-                                c++;
-
-                }
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
-                r = sd_bus_message_exit_container(reply);
-                if (r < 0)
-                        return bus_log_parse_error(r);
-        }
-
-        (void) pager_open(arg_pager_flags);
-
-        typesafe_qsort(units, c, compare_unit_file_list);
-        r = output_unit_file_list(units, c);
-        if (r < 0)
-                return r;
-
-        if (install_client_side())
-                for (unit = units; unit < units + c; unit++)
-                        free(unit->path);
-
-        if (c == 0)
-                return -ENOENT;
-
-        return 0;
-}
-
-static int list_dependencies_print(const char *name, int level, unsigned branches, bool last) {
-        _cleanup_free_ char *n = NULL;
-        size_t max_len = MAX(columns(),20u);
-        size_t len = 0;
-        int i;
-
-        if (!arg_plain) {
-
-                for (i = level - 1; i >= 0; i--) {
-                        len += 2;
-                        if (len > max_len - 3 && !arg_full) {
-                                printf("%s...\n",max_len % 2 ? "" : " ");
-                                return 0;
-                        }
-                        printf("%s", special_glyph(branches & (1 << i) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
-                }
-                len += 2;
-
-                if (len > max_len - 3 && !arg_full) {
-                        printf("%s...\n",max_len % 2 ? "" : " ");
-                        return 0;
-                }
-
-                printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
-        }
-
-        if (arg_full) {
-                printf("%s\n", name);
-                return 0;
-        }
-
-        n = ellipsize(name, max_len-len, 100);
-        if (!n)
-                return log_oom();
-
-        printf("%s\n", n);
-        return 0;
-}
-
-static int list_dependencies_compare(char * const *a, char * const *b) {
-        if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
-                return 1;
-        if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
-                return -1;
-
-        return strcasecmp(*a, *b);
-}
-
-static int list_dependencies_one(
-                sd_bus *bus,
-                const char *name,
-                int level,
-                char ***units,
-                unsigned branches) {
-
-        _cleanup_strv_free_ char **deps = NULL;
-        char **c;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(units);
-
-        r = strv_extend(units, name);
-        if (r < 0)
-                return log_oom();
-
-        r = list_dependencies_get_dependencies(bus, name, &deps);
-        if (r < 0)
-                return r;
-
-        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
-
-        STRV_FOREACH(c, deps) {
-                if (strv_contains(*units, *c)) {
-                        if (!arg_plain) {
-                                printf("  ");
-                                r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
-                                if (r < 0)
-                                        return r;
-                        }
-                        continue;
-                }
-
-                if (arg_plain)
-                        printf("  ");
-                else {
-                        UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
-                        const char *on;
-
-                        (void) get_state_one_unit(bus, *c, &active_state);
-
-                        switch (active_state) {
-                        case UNIT_ACTIVE:
-                        case UNIT_RELOADING:
-                        case UNIT_ACTIVATING:
-                                on = ansi_highlight_green();
-                                break;
-
-                        case UNIT_INACTIVE:
-                        case UNIT_DEACTIVATING:
-                                on = ansi_normal();
-                                break;
-
-                        default:
-                                on = ansi_highlight_red();
-                                break;
-                        }
-
-                        printf("%s%s%s ", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), ansi_normal());
-                }
-
-                r = list_dependencies_print(*c, level, branches, c[1] == NULL);
-                if (r < 0)
-                        return r;
-
-                if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
-                       r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
-                       if (r < 0)
-                               return r;
-                }
-        }
-
-        if (!arg_plain)
-                strv_remove(*units, name);
-
-        return 0;
-}
-
-static int list_dependencies(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **units = NULL, **done = NULL;
-        char **u, **patterns;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        patterns = strv_skip(argv, 1);
-        if (strv_isempty(patterns)) {
-                units = strv_new(SPECIAL_DEFAULT_TARGET);
-                if (!units)
-                        return log_oom();
-        } else {
-                r = expand_names(bus, patterns, NULL, &units, NULL);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to expand names: %m");
-        }
-
-        (void) pager_open(arg_pager_flags);
-
-        STRV_FOREACH(u, units) {
-                if (u != units)
-                        puts("");
-
-                puts(*u);
-                r = list_dependencies_one(bus, *u, 0, &done, 0);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-struct machine_info {
-        bool is_host;
-        char *name;
-        char *state;
-        char *control_group;
-        uint32_t n_failed_units;
-        uint32_t n_jobs;
-        usec_t timestamp;
-};
-
-static const struct bus_properties_map machine_info_property_map[] = {
-        { "SystemState",        "s", NULL, offsetof(struct machine_info, state)          },
-        { "NJobs",              "u", NULL, offsetof(struct machine_info, n_jobs)         },
-        { "NFailedUnits",       "u", NULL, offsetof(struct machine_info, n_failed_units) },
-        { "ControlGroup",       "s", NULL, offsetof(struct machine_info, control_group)  },
-        { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp)      },
-        {}
-};
-
-static void machine_info_clear(struct machine_info *info) {
-        assert(info);
-
-        free(info->name);
-        free(info->state);
-        free(info->control_group);
-        zero(*info);
-}
-
-static void free_machines_list(struct machine_info *machine_infos, int n) {
-        int i;
-
-        if (!machine_infos)
-                return;
-
-        for (i = 0; i < n; i++)
-                machine_info_clear(&machine_infos[i]);
-
-        free(machine_infos);
-}
-
-static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
-        int r;
-
-        r = CMP(b->is_host, a->is_host);
-        if (r != 0)
-                return r;
-
-        return strcasecmp(a->name, b->name);
-}
-
-static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
-        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
-        int r;
-
-        assert(mi);
-
-        if (!bus) {
-                r = sd_bus_open_system_machine(&container, mi->name);
-                if (r < 0)
-                        return r;
-
-                bus = container;
-        }
-
-        r = bus_map_all_properties(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        machine_info_property_map,
-                        BUS_MAP_STRDUP,
-                        NULL,
-                        NULL,
-                        mi);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static bool output_show_machine(const char *name, char **patterns) {
-        return strv_fnmatch_or_empty(patterns, name, FNM_NOESCAPE);
-}
-
-static int get_machine_list(
-                sd_bus *bus,
-                struct machine_info **_machine_infos,
-                char **patterns) {
-
-        struct machine_info *machine_infos = NULL;
-        _cleanup_strv_free_ char **m = NULL;
-        _cleanup_free_ char *hn = NULL;
-        size_t sz = 0;
-        char **i;
-        int c = 0, r;
-
-        hn = gethostname_malloc();
-        if (!hn)
-                return log_oom();
-
-        if (output_show_machine(hn, patterns)) {
-                if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
-                        return log_oom();
-
-                machine_infos[c].is_host = true;
-                machine_infos[c].name = TAKE_PTR(hn);
-
-                (void) get_machine_properties(bus, &machine_infos[c]);
-                c++;
-        }
-
-        r = sd_get_machine_names(&m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get machine list: %m");
-
-        STRV_FOREACH(i, m) {
-                _cleanup_free_ char *class = NULL;
-
-                if (!output_show_machine(*i, patterns))
-                        continue;
-
-                sd_machine_get_class(*i, &class);
-                if (!streq_ptr(class, "container"))
-                        continue;
-
-                if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
-                        free_machines_list(machine_infos, c);
-                        return log_oom();
-                }
-
-                machine_infos[c].is_host = false;
-                machine_infos[c].name = strdup(*i);
-                if (!machine_infos[c].name) {
-                        free_machines_list(machine_infos, c);
-                        return log_oom();
-                }
-
-                (void) get_machine_properties(NULL, &machine_infos[c]);
-                c++;
-        }
-
-        *_machine_infos = machine_infos;
-        return c;
-}
-
-static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        struct machine_info *m;
-        bool state_missing = false;
-        int r;
-
-        assert(machine_infos || n == 0);
-
-        table = table_new("", "name", "state", "failed", "jobs");
-        if (!table)
-                return log_oom();
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_plain) {
-                /* Hide the 'glyph' column when --plain is requested */
-                r = table_hide_column_from_display(table, 0);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to hide column: %m");
-        }
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        for (m = machine_infos; m < machine_infos + n; m++) {
-                _cleanup_free_ char *mname = NULL;
-                const char *on_state = "", *on_failed = "";
-                bool circle = false;
-
-                if (streq_ptr(m->state, "degraded")) {
-                        on_state = ansi_highlight_red();
-                        circle = true;
-                } else if (!streq_ptr(m->state, "running")) {
-                        on_state = ansi_highlight_yellow();
-                        circle = true;
-                }
-
-                if (m->n_failed_units > 0)
-                        on_failed = ansi_highlight_red();
-                else
-                        on_failed =  "";
-
-                if (!m->state)
-                        state_missing = true;
-
-                if (m->is_host)
-                        mname = strjoin(strna(m->name), " (host)");
-
-                r = table_add_many(table,
-                                   TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
-                                   TABLE_SET_COLOR, on_state,
-                                   TABLE_STRING, m->is_host ? mname : strna(m->name),
-                                   TABLE_STRING, strna(m->state),
-                                   TABLE_SET_COLOR, on_state,
-                                   TABLE_UINT32, m->n_failed_units,
-                                   TABLE_SET_COLOR, on_failed,
-                                   TABLE_UINT32, m->n_jobs);
-                if (r < 0)
-                        return table_log_add_error(r);
-        }
-
-        r = output_table(table);
-        if (r < 0)
-                return r;
-
-        if (!arg_no_legend) {
-                printf("\n");
-                if (state_missing && geteuid() != 0)
-                        printf("Notice: some information only available to privileged users was not shown.\n");
-                printf("%u machines listed.\n", n);
-        }
-
-        return 0;
-}
-
-static int list_machines(int argc, char *argv[], void *userdata) {
-        struct machine_info *machine_infos = NULL;
-        sd_bus *bus;
-        int r, rc;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        typesafe_qsort(machine_infos, r, compare_machine_info);
-        rc = output_machines_list(machine_infos, r);
-        free_machines_list(machine_infos, r);
-
-        return rc;
-}
-
-static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
-        char **ret = data;
-
-        if (streq(key, "systemd.unit")) {
-                if (proc_cmdline_value_missing(key, value))
-                        return 0;
-                if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
-                        log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
-                        return 0;
-                }
-
-                return free_and_strdup_warn(ret, key);
-
-        } else if (!value) {
-                if (runlevel_to_target(key))
-                        return free_and_strdup_warn(ret, key);
-        }
-
-        return 0;
-}
-
-static void emit_cmdline_warning(void) {
-        if (arg_quiet || arg_root)
-                /* don't bother checking the commandline if we're operating on a container */
-                return;
-
-        _cleanup_free_ char *override = NULL;
-        int r;
-
-        r = proc_cmdline_parse(parse_proc_cmdline_item, &override, 0);
-        if (r < 0)
-                log_debug_errno(r, "Failed to parse kernel command line, ignoring: %m");
-        if (override)
-                log_notice("Note: found \"%s\" on the kernel commandline, which overrides the default unit.",
-                           override);
-}
-
-static int determine_default(char **ret_name) {
-        int r;
-
-        if (install_client_side()) {
-                r = unit_file_get_default(arg_scope, arg_root, ret_name);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get default target: %m");
-                return 0;
-
-        } else {
-                sd_bus *bus;
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                const char *name;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                r = bus_call_method(bus, bus_systemd_mgr, "GetDefaultTarget", &error, &reply, NULL);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
-
-                r = sd_bus_message_read(reply, "s", &name);
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
-                return free_and_strdup_warn(ret_name, name);
-        }
-}
-
-static int get_default(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ char *name = NULL;
-        int r;
-
-        r = determine_default(&name);
-        if (r < 0)
-                return r;
-
-        printf("%s\n", name);
-
-        emit_cmdline_warning();
-
-        return 0;
-}
-
-static int set_default(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ char *unit = NULL;
-        UnitFileChange *changes = NULL;
-        size_t n_changes = 0;
-        int r;
-
-        assert(argc >= 2);
-        assert(argv);
-
-        r = unit_name_mangle_with_suffix(argv[1], "set-default",
-                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
-                                         ".target", &unit);
-        if (r < 0)
-                return log_error_errno(r, "Failed to mangle unit name: %m");
-
-        if (install_client_side()) {
-                r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes);
-                unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
-
-                if (r > 0)
-                        r = 0;
-        } else {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                sd_bus *bus;
-
-                polkit_agent_open_maybe();
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                r = bus_call_method(bus, bus_systemd_mgr, "SetDefaultTarget", &error, &reply, "sb", unit, 1);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
-
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
-                if (r < 0)
-                        goto finish;
-
-                /* Try to reload if enabled */
-                if (!arg_no_reload)
-                        r = daemon_reload(argc, argv, userdata);
-                else
-                        r = 0;
-        }
-
-        emit_cmdline_warning();
-
-        if (!arg_quiet) {
-                _cleanup_free_ char *final = NULL;
-
-                r = determine_default(&final);
-                if (r < 0)
-                        return r;
-
-                if (!streq(final, unit))
-                        log_notice("Note: \"%s\" is the default unit (possibly a runtime override).", final);
-        }
-
-finish:
-        unit_file_changes_free(changes, n_changes);
-
-        return r;
-}
-
-static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const char *method, const char *prefix) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *name, *type;
-        uint32_t other_id;
-        int r;
-
-        assert(bus);
-
-        r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
-        if (r < 0)
-                return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
-
-        r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
-                _cleanup_free_ char *row = NULL;
-                int rc;
-
-                if (asprintf(&row, "%s %u (%s/%s)", prefix, other_id, name, type) < 0)
-                        return log_oom();
-
-                rc = table_add_many(table,
-                                    TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
-                                    TABLE_STRING, row,
-                                    TABLE_EMPTY,
-                                    TABLE_EMPTY);
-                if (rc < 0)
-                        return table_log_add_error(r);
-        }
-
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return 0;
-}
-
-struct job_info {
-        uint32_t id;
-        const char *name, *type, *state;
-};
-
-static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
-        _cleanup_(table_unrefp) Table *table = NULL;
-        const struct job_info *j;
-        const char *on, *off;
-        int r;
-
-        assert(n == 0 || jobs);
-
-        if (n == 0) {
-                if (!arg_no_legend) {
-                        on = ansi_highlight_green();
-                        off = ansi_normal();
-
-                        printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
-                }
-                return 0;
-        }
-
-        (void) pager_open(arg_pager_flags);
-
-        table = table_new("job", "unit", "type", "state");
-        if (!table)
-                return log_oom();
-
-        table_set_header(table, !arg_no_legend);
-        if (arg_full)
-                table_set_width(table, 0);
-
-        (void) table_set_empty_string(table, "-");
-
-        for (j = jobs; j < jobs + n; j++) {
-                if (streq(j->state, "running"))
-                        on = ansi_highlight();
-                else
-                        on =  "";
-
-                r = table_add_many(table,
-                                   TABLE_UINT, j->id,
-                                   TABLE_STRING, j->name,
-                                   TABLE_SET_COLOR, on,
-                                   TABLE_STRING, j->type,
-                                   TABLE_STRING, j->state,
-                                   TABLE_SET_COLOR, on);
-                if (r < 0)
-                        return table_log_add_error(r);
-
-                if (arg_jobs_after)
-                        output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
-                if (arg_jobs_before)
-                        output_waiting_jobs(bus, table, j->id, "GetJobBefore", "\tblocking job");
-        }
-
-        r = table_print(table, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
-
-        if (!arg_no_legend) {
-                on = ansi_highlight();
-                off = ansi_normal();
-
-                printf("\n%s%u jobs listed%s.\n", on, n, off);
-        }
-
-        return 0;
-}
-
-static bool output_show_job(struct job_info *job, char **patterns) {
-        return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
-}
-
-static int list_jobs(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_free_ struct job_info *jobs = NULL;
-        const char *name, *type, *state;
-        bool skipped = false;
-        size_t size = 0;
-        unsigned c = 0;
-        sd_bus *bus;
-        uint32_t id;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
-
-        r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, NULL, NULL)) > 0) {
-                struct job_info job = { id, name, type, state };
-
-                if (!output_show_job(&job, strv_skip(argv, 1))) {
-                        skipped = true;
-                        continue;
-                }
-
-                if (!GREEDY_REALLOC(jobs, size, c + 1))
-                        return log_oom();
-
-                jobs[c++] = job;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        (void) pager_open(arg_pager_flags);
-
-        return output_jobs_list(bus, jobs, c, skipped);
-}
-
-static int cancel_job(int argc, char *argv[], void *userdata) {
-        sd_bus *bus;
-        char **name;
-        int r;
-
-        if (argc <= 1)
-                return trivial_method(argc, argv, userdata);
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        STRV_FOREACH(name, strv_skip(argv, 1)) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                uint32_t id;
-                int q;
-
-                q = safe_atou32(*name, &id);
-                if (q < 0)
-                        return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
-
-                q = bus_call_method(bus, bus_systemd_mgr, "CancelJob", &error, NULL, "u", id);
-                if (q < 0) {
-                        log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
-                        if (r == 0)
-                                r = q;
-                }
-        }
-
-        return r;
-}
-
-static int need_daemon_reload(sd_bus *bus, const char *unit) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *path;
-        int b, r;
-
-        /* We ignore all errors here, since this is used to show a
-         * warning only */
-
-        /* We don't use unit_dbus_path_from_name() directly since we
-         * don't want to load the unit if it isn't loaded. */
-
-        r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(reply, "o", &path);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_get_property_trivial(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Unit",
-                        "NeedDaemonReload",
-                        NULL,
-                        'b', &b);
-        if (r < 0)
-                return r;
-
-        return b;
-}
-
-static void warn_unit_file_changed(const char *name) {
-        assert(name);
-
-        log_warning("%sWarning:%s The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
-                    ansi_highlight_red(),
-                    ansi_normal(),
-                    name,
-                    arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
-}
-
-static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
-        char **p;
-
-        assert(lp);
-        assert(unit_name);
-
-        STRV_FOREACH(p, lp->search_path) {
-                _cleanup_free_ char *path = NULL, *lpath = NULL;
-                int r;
-
-                path = path_join(*p, unit_name);
-                if (!path)
-                        return log_oom();
-
-                r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
-                if (r == -ENOENT)
-                        continue;
-                if (r == -ENOMEM)
-                        return log_oom();
-                if (r < 0)
-                        return log_error_errno(r, "Failed to access path \"%s\": %m", path);
-
-                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 **ret_fragment_path,
-                char **ret_template) {
-
-        _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, &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;
-
-                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, t, ret_fragment_path);
-        if (r < 0)
-                return r;
-
-        if (ret_template)
-                *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
-
-        return r;
-}
-
-static int unit_find_paths(
-                sd_bus *bus,
-                const char *unit_name,
-                LookupPaths *lp,
-                bool force_client_side,
-                char **ret_fragment_path,
-                char ***ret_dropin_paths) {
-
-        _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 *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(ret_fragment_path);
-        assert(lp);
-
-        /* 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 *load_state = NULL, *dbus_path = NULL;
-
-                dbus_path = unit_dbus_path_from_name(unit_name);
-                if (!dbus_path)
-                        return log_oom();
-
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                dbus_path,
-                                "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 (!STR_IN_SET(load_state, "loaded", "bad-setting"))
-                        return -EKEYREJECTED;
-
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                dbus_path,
-                                "org.freedesktop.systemd1.Unit",
-                                "FragmentPath",
-                                &error,
-                                &path);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
-
-                if (ret_dropin_paths) {
-                        r = sd_bus_get_property_strv(
-                                        bus,
-                                        "org.freedesktop.systemd1",
-                                        dbus_path,
-                                        "org.freedesktop.systemd1.Unit",
-                                        "DropInPaths",
-                                        &error,
-                                        &dropins);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
-                }
-        } else {
-                const char *_path;
-                _cleanup_set_free_free_ Set *names = NULL;
-
-                if (!cached_name_map) {
-                        r = unit_file_build_name_map(lp, NULL, &cached_id_map, &cached_name_map, NULL);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = unit_file_find_fragment(cached_id_map, cached_name_map, unit_name, &_path, &names);
-                if (r < 0)
-                        return r;
-
-                if (_path) {
-                        path = strdup(_path);
-                        if (!path)
-                                return log_oom();
-                }
-
-                if (ret_dropin_paths) {
-                        r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL,
-                                                        ".d", ".conf",
-                                                        NULL, names, &dropins);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        if (isempty(path)) {
-                *ret_fragment_path = NULL;
-                r = 0;
-        } else {
-                *ret_fragment_path = TAKE_PTR(path);
-                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);
-
-        return r;
-}
-
-static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *buf = NULL, *dbus_path = NULL;
-        UnitActiveState state;
-        int r;
-
-        assert(name);
-        assert(active_state);
-
-        dbus_path = unit_dbus_path_from_name(name);
-        if (!dbus_path)
-                return log_oom();
-
-        r = sd_bus_get_property_string(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        dbus_path,
-                        "org.freedesktop.systemd1.Unit",
-                        "ActiveState",
-                        &error,
-                        &buf);
-        if (r < 0)
-                return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
-
-        state = unit_active_state_from_string(buf);
-        if (state < 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit state '%s' for: %s", buf, name);
-
-        *active_state = state;
-        return 0;
-}
-
-static int unit_is_masked(sd_bus *bus, LookupPaths *lp, const char *name) {
-        _cleanup_free_ char *load_state = NULL;
-        int r;
-
-        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
-                _cleanup_free_ char *path = NULL;
-
-                /* A template cannot be loaded, but it can be still masked, so
-                 * we need to use a different method. */
-
-                r = unit_file_find_path(lp, name, &path);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return false;
-                return null_or_empty_path(path);
-        }
-
-        r = unit_load_state(bus, name, &load_state);
-        if (r < 0)
-                return r;
-
-        return streq(load_state, "masked");
-}
-
-static int check_triggering_units(sd_bus *bus, const char *name) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *n = NULL, *dbus_path = NULL, *load_state = NULL;
-        _cleanup_strv_free_ char **triggered_by = NULL;
-        bool print_warning_label = true;
-        UnitActiveState active_state;
-        char **i;
-        int r;
-
-        r = unit_name_mangle(name, 0, &n);
-        if (r < 0)
-                return log_error_errno(r, "Failed to mangle unit name: %m");
-
-        r = unit_load_state(bus, name, &load_state);
-        if (r < 0)
-                return r;
-
-        if (streq(load_state, "masked"))
-                return 0;
-
-        dbus_path = unit_dbus_path_from_name(n);
-        if (!dbus_path)
-                return log_oom();
-
-        r = sd_bus_get_property_strv(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        dbus_path,
-                        "org.freedesktop.systemd1.Unit",
-                        "TriggeredBy",
-                        &error,
-                        &triggered_by);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
-
-        STRV_FOREACH(i, triggered_by) {
-                r = get_state_one_unit(bus, *i, &active_state);
-                if (r < 0)
-                        return r;
-
-                if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
-                        continue;
-
-                if (print_warning_label) {
-                        log_warning("Warning: Stopping %s, but it can still be activated by:", n);
-                        print_warning_label = false;
-                }
-
-                log_warning("  %s", *i);
-        }
-
-        return 0;
-}
-
-static const struct {
-        const char *verb;      /* systemctl verb */
-        const char *method;    /* Name of the specific D-Bus method */
-        const char *job_type;  /* Job type when passing to the generic EnqueueUnitJob() method */
-} unit_actions[] = {
-        { "start",                 "StartUnit",              "start"                 },
-        { "stop",                  "StopUnit",               "stop"                  },
-        { "condstop",              "StopUnit",               "stop"                  }, /* legacy alias */
-        { "reload",                "ReloadUnit",             "reload"                },
-        { "restart",               "RestartUnit",            "restart"               },
-        { "try-restart",           "TryRestartUnit",         "try-restart"           },
-        { "condrestart",           "TryRestartUnit",         "try-restart"           }, /* legacy alias */
-        { "reload-or-restart",     "ReloadOrRestartUnit",    "reload-or-restart"     },
-        { "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
-        { "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
-        { "condreload",            "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
-        { "force-reload",          "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
-};
-
-static const char *verb_to_method(const char *verb) {
-       size_t i;
-
-       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
-                if (streq_ptr(unit_actions[i].verb, verb))
-                        return unit_actions[i].method;
-
-       return "StartUnit";
-}
-
-static const char *verb_to_job_type(const char *verb) {
-       size_t i;
-
-       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
-                if (streq_ptr(unit_actions[i].verb, verb))
-                        return unit_actions[i].job_type;
-
-       return "start";
-}
-
-static int start_unit_one(
-                sd_bus *bus,
-                const char *method,    /* When using classic per-job bus methods */
-                const char *job_type,  /* When using new-style EnqueueUnitJob() */
-                const char *name,
-                const char *mode,
-                sd_bus_error *error,
-                BusWaitForJobs *w,
-                BusWaitForUnits *wu) {
-
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *path;
-        bool done = false;
-        int r;
-
-        assert(method);
-        assert(name);
-        assert(mode);
-        assert(error);
-
-        log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
-                  arg_dry_run ? "Would execute" : "Executing",
-                  method, name, mode);
-
-        if (arg_dry_run)
-                return 0;
-
-        if (arg_show_transaction) {
-                _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
-
-                /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
-                r = bus_call_method(
-                                bus,
-                                bus_systemd_mgr,
-                                "EnqueueUnitJob",
-                                &enqueue_error,
-                                &reply,
-                                "sss",
-                                name, job_type, mode);
-                if (r < 0) {
-                        if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
-                                (void) sd_bus_error_move(error, &enqueue_error);
-                                goto fail;
-                        }
-
-                        /* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
-                        log_notice("--show-transaction not supported by this service manager, proceeding without.");
-                } else {
-                        const char *u, *jt;
-                        uint32_t id;
-
-                        r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
-
-                        r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-                        for (;;) {
-                                r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
-                                if (r < 0)
-                                        return bus_log_parse_error(r);
-                                if (r == 0)
-                                        break;
-
-                                log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
-                        }
-
-                        r = sd_bus_message_exit_container(reply);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        done = true;
-                }
-        }
-
-        if (!done) {
-                r = bus_call_method(bus, bus_systemd_mgr, method, error, &reply, "ss", name, mode);
-                if (r < 0)
-                        goto fail;
-
-                r = sd_bus_message_read(reply, "o", &path);
-                if (r < 0)
-                        return bus_log_parse_error(r);
-        }
-
-        if (need_daemon_reload(bus, name) > 0)
-                warn_unit_file_changed(name);
-
-        if (w) {
-                log_debug("Adding %s to the set", path);
-                r = bus_wait_for_jobs_add(w, path);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to watch job for %s: %m", name);
-        }
-
-        if (wu) {
-                r = bus_wait_for_units_add_unit(wu, name, BUS_WAIT_FOR_INACTIVE|BUS_WAIT_NO_JOB, NULL, NULL);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to watch unit %s: %m", name);
-        }
-
-        return 0;
-
-fail:
-        /* There's always a fallback possible for legacy actions. */
-        if (arg_action != ACTION_SYSTEMCTL)
-                return r;
-
-        log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
-
-        if (!sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT,
-                                           BUS_ERROR_UNIT_MASKED,
-                                           BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
-                log_error("See %s logs and 'systemctl%s status%s %s' for details.",
-                          arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
-                          arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
-                          name[0] == '-' ? " --" : "",
-                          name);
-
-        return r;
-}
-
-static const struct {
-        const char *target;
-        const char *verb;
-        const char *mode;
-} action_table[_ACTION_MAX] = {
-        [ACTION_HALT]                   = { SPECIAL_HALT_TARGET,                   "halt",                   "replace-irreversibly" },
-        [ACTION_POWEROFF]               = { SPECIAL_POWEROFF_TARGET,               "poweroff",               "replace-irreversibly" },
-        [ACTION_REBOOT]                 = { SPECIAL_REBOOT_TARGET,                 "reboot",                 "replace-irreversibly" },
-        [ACTION_KEXEC]                  = { SPECIAL_KEXEC_TARGET,                  "kexec",                  "replace-irreversibly" },
-        [ACTION_RUNLEVEL2]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
-        [ACTION_RUNLEVEL3]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
-        [ACTION_RUNLEVEL4]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
-        [ACTION_RUNLEVEL5]              = { SPECIAL_GRAPHICAL_TARGET,              NULL,                     "isolate"              },
-        [ACTION_RESCUE]                 = { SPECIAL_RESCUE_TARGET,                 "rescue",                 "isolate"              },
-        [ACTION_EMERGENCY]              = { SPECIAL_EMERGENCY_TARGET,              "emergency",              "isolate"              },
-        [ACTION_DEFAULT]                = { SPECIAL_DEFAULT_TARGET,                "default",                "isolate"              },
-        [ACTION_EXIT]                   = { SPECIAL_EXIT_TARGET,                   "exit",                   "replace-irreversibly" },
-        [ACTION_SUSPEND]                = { SPECIAL_SUSPEND_TARGET,                "suspend",                "replace-irreversibly" },
-        [ACTION_HIBERNATE]              = { SPECIAL_HIBERNATE_TARGET,              "hibernate",              "replace-irreversibly" },
-        [ACTION_HYBRID_SLEEP]           = { SPECIAL_HYBRID_SLEEP_TARGET,           "hybrid-sleep",           "replace-irreversibly" },
-        [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
-};
-
-static enum action verb_to_action(const char *verb) {
-        enum action i;
-
-        for (i = 0; i < _ACTION_MAX; i++)
-                if (streq_ptr(action_table[i].verb, verb))
-                        return i;
-
-        return _ACTION_INVALID;
-}
-
-static const char** make_extra_args(const char *extra_args[static 4]) {
-        size_t n = 0;
-
-        assert(extra_args);
-
-        if (arg_scope != UNIT_FILE_SYSTEM)
-                extra_args[n++] = "--user";
-
-        if (arg_transport == BUS_TRANSPORT_REMOTE) {
-                extra_args[n++] = "-H";
-                extra_args[n++] = arg_host;
-        } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
-                extra_args[n++] = "-M";
-                extra_args[n++] = arg_host;
-        } else
-                assert(arg_transport == BUS_TRANSPORT_LOCAL);
-
-        extra_args[n] = NULL;
-        return extra_args;
-}
-
-static int start_unit(int argc, char *argv[], void *userdata) {
-        _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *wu = NULL;
-        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
-        const char *method, *job_type, *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;
-        char **name;
-
-        if (arg_wait && !STR_IN_SET(argv[0], "start", "restart"))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "--wait may only be used with the 'start' or 'restart' commands.");
-
-        /* we cannot do sender tracking on the private bus, so we need the full
-         * one for RefUnit to implement --wait */
-        r = acquire_bus(arg_wait ? BUS_FULL : BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        ask_password_agent_open_maybe();
-        polkit_agent_open_maybe();
-
-        if (arg_action == ACTION_SYSTEMCTL) {
-                enum action action;
-
-                action = verb_to_action(argv[0]);
-
-                if (action != _ACTION_INVALID) {
-                        /* A command in style "systemctl reboot", "systemctl poweroff", … */
-                        method = "StartUnit";
-                        job_type = "start";
-                        mode = action_table[action].mode;
-                        one_name = action_table[action].target;
-                } else {
-                        if (streq(argv[0], "isolate")) {
-                                /* A "systemctl isolate <unit1> <unit2> …" command */
-                                method = "StartUnit";
-                                job_type = "start";
-                                mode = "isolate";
-                                suffix = ".target";
-                        } else {
-                                /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
-                                method = verb_to_method(argv[0]);
-                                job_type = verb_to_job_type(argv[0]);
-                                mode = arg_job_mode;
-                        }
-                        one_name = NULL;
-                }
-        } else {
-                /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
-                assert(arg_action >= 0 && arg_action < _ACTION_MAX);
-                assert(action_table[arg_action].target);
-                assert(action_table[arg_action].mode);
-
-                method = "StartUnit";
-                job_type = "start";
-                mode = action_table[arg_action].mode;
-                one_name = action_table[arg_action].target;
-        }
-
-        if (one_name) {
-                names = strv_new(one_name);
-                if (!names)
-                        return log_oom();
-        } else {
-                bool expanded;
-
-                r = expand_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to expand names: %m");
-
-                if (!arg_all && expanded && streq(job_type, "start") && !arg_quiet) {
-                        log_warning("Warning: %ssystemctl start called with a glob pattern.%s",
-                                    ansi_highlight_red(),
-                                    ansi_normal());
-                        log_notice("Hint: unit globs expand to loaded units, so start will usually have no effect.\n"
-                                   "      Passing --all will also load units which are pulled in by other units.\n"
-                                   "      See systemctl(1) for more details.");
-                }
-        }
-
-        if (!arg_no_block) {
-                r = bus_wait_for_jobs_new(bus, &w);
-                if (r < 0)
-                        return log_error_errno(r, "Could not watch jobs: %m");
-        }
-
-        if (arg_wait) {
-                r = bus_call_method_async(bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to enable subscription: %m");
-
-                r = bus_wait_for_units_new(bus, &wu);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to allocate unit watch context: %m");
-        }
-
-        STRV_FOREACH(name, names) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
-                r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
-                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) {
-                const char* extra_args[4];
-
-                r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
-                if (r < 0)
-                        return r;
-
-                /* When stopping units, warn if they can still be triggered by
-                 * another active unit (socket, path, timer) */
-                if (!arg_quiet)
-                        STRV_FOREACH(name, stopped_units)
-                                (void) check_triggering_units(bus, *name);
-        }
-
-        if (arg_wait) {
-                r = bus_wait_for_units_run(wu);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to wait for units: %m");
-                if (r == BUS_WAIT_FAILURE && ret == EXIT_SUCCESS)
-                        ret = EXIT_FAILURE;
-        }
-
-        return ret;
-}
-
-#if ENABLE_LOGIND
-static int logind_set_wall_message(void) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        _cleanup_free_ char *m = NULL;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        m = strv_join(arg_wall, " ");
-        if (!m)
-                return log_oom();
-
-        log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
-        if (arg_dry_run)
-                return 0;
-
-        r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
-        if (r < 0)
-                return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
-        return 0;
-}
-#endif
-
-/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
-static int logind_reboot(enum action a) {
-#if ENABLE_LOGIND
-        static const struct {
-                const char *method;
-                const char *description;
-        } actions[_ACTION_MAX] = {
-                [ACTION_POWEROFF]               = { "PowerOff",             "power off system"                },
-                [ACTION_REBOOT]                 = { "Reboot",               "reboot system"                   },
-                [ACTION_HALT]                   = { "Halt",                 "halt system"                     },
-                [ACTION_SUSPEND]                = { "Suspend",              "suspend system"                  },
-                [ACTION_HIBERNATE]              = { "Hibernate",            "hibernate system"                },
-                [ACTION_HYBRID_SLEEP]           = { "HybridSleep",          "put system into hybrid sleep"    },
-                [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
-        };
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
-                return -EINVAL;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-        (void) logind_set_wall_message();
-
-        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
-
-        if (arg_dry_run)
-                return 0;
-
-        r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
-        if (r < 0)
-                return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
-
-        return 0;
-#else
-        return -ENOSYS;
-#endif
-}
-
-static int logind_check_inhibitors(enum action a) {
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_strv_free_ char **sessions = NULL;
-        const char *what, *who, *why, *mode;
-        uint32_t uid, pid;
-        sd_bus *bus;
-        unsigned c = 0;
-        char **s;
-        int r;
-
-        if (arg_ignore_inhibitors || arg_force > 0)
-                return 0;
-
-        if (arg_when > 0)
-                return 0;
-
-        if (geteuid() == 0)
-                return 0;
-
-        if (!on_tty())
-                return 0;
-
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                return 0;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
-        if (r < 0)
-                /* If logind is not around, then there are no inhibitors... */
-                return 0;
-
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
-                _cleanup_free_ char *comm = NULL, *user = NULL;
-                _cleanup_strv_free_ char **sv = NULL;
-
-                if (!streq(mode, "block"))
-                        continue;
-
-                sv = strv_split(what, ":");
-                if (!sv)
-                        return log_oom();
-
-                if (!pid_is_valid((pid_t) pid))
-                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
-
-                if (!strv_contains(sv,
-                                   IN_SET(a,
-                                          ACTION_HALT,
-                                          ACTION_POWEROFF,
-                                          ACTION_REBOOT,
-                                          ACTION_KEXEC) ? "shutdown" : "sleep"))
-                        continue;
-
-                get_process_comm(pid, &comm);
-                user = uid_to_name(uid);
-
-                log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
-                            who, (pid_t) pid, strna(comm), strna(user), why);
-
-                c++;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        /* Check for current sessions */
-        sd_get_sessions(&sessions);
-        STRV_FOREACH(s, sessions) {
-                _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
-
-                if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
-                        continue;
-
-                if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
-                        continue;
-
-                if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
-                        continue;
-
-                sd_session_get_tty(*s, &tty);
-                sd_session_get_seat(*s, &seat);
-                sd_session_get_service(*s, &service);
-                user = uid_to_name(uid);
-
-                log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
-                c++;
-        }
-
-        if (c <= 0)
-                return 0;
-
-        log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
-                  action_table[a].verb);
-
-        return -EPERM;
-#else
-        return 0;
-#endif
-}
-
-static int prepare_firmware_setup(void) {
-
-        if (!arg_firmware_setup)
-                return 0;
-
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
-        if (r < 0)
-                return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
-
-        return 0;
-#else
-        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
-                               "Booting into firmware setup not supported.");
-#endif
-}
-
-static int prepare_boot_loader_menu(void) {
-
-        if (arg_boot_loader_menu == USEC_INFINITY)
-                return 0;
-
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
-        if (r < 0)
-                return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
-
-        return 0;
-#else
-        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
-                               "Booting into boot loader menu not supported.");
-#endif
-}
-
-static int prepare_boot_loader_entry(void) {
-
-        if (!arg_boot_loader_entry)
-                return 0;
-
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
-        if (r < 0)
-                return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
-
-        return 0;
-#else
-        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
-                               "Booting into boot loader entry not supported.");
-#endif
-}
-
-static int load_kexec_kernel(void) {
-        _cleanup_(boot_config_free) BootConfig config = {};
-        _cleanup_free_ char *kernel = NULL, *initrd = NULL, *options = NULL;
-        const BootEntry *e;
-        pid_t pid;
-        int r;
-
-        if (kexec_loaded()) {
-                log_debug("Kexec kernel already loaded.");
-                return 0;
-        }
-
-        if (access(KEXEC, X_OK) < 0)
-                return log_error_errno(errno, KEXEC" is not available: %m");
-
-        r = boot_entries_load_config_auto(NULL, NULL, &config);
-        if (r == -ENOKEY)
-                /* The call doesn't log about ENOKEY, let's do so here. */
-                return log_error_errno(r,
-                                       "No kexec kernel loaded and autodetection failed.\n%s",
-                                       is_efi_boot()
-                                       ? "Cannot automatically load kernel: ESP partition mount point not found."
-                                       : "Automatic loading works only on systems booted with EFI.");
-        if (r < 0)
-                return r;
-
-        e = boot_config_default_entry(&config);
-        if (!e)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
-                                       "No boot loader entry suitable as default, refusing to guess.");
-
-        log_debug("Found default boot loader entry in file \"%s\"", e->path);
-
-        if (!e->kernel)
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "Boot entry does not refer to Linux kernel, which is not supported currently.");
-        if (strv_length(e->initrd) > 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "Boot entry specifies multiple initrds, which is not supported currently.");
-
-        kernel = path_join(e->root, e->kernel);
-        if (!kernel)
-                return log_oom();
-
-        if (!strv_isempty(e->initrd)) {
-                initrd = path_join(e->root, e->initrd[0]);
-                if (!initrd)
-                        return log_oom();
-        }
-
-        options = strv_join(e->options, " ");
-        if (!options)
-                return log_oom();
-
-        log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
-                 "%s "KEXEC" --load \"%s\" --append \"%s\"%s%s%s",
-                 arg_dry_run ? "Would run" : "Running",
-                 kernel,
-                 options,
-                 initrd ? " --initrd \"" : NULL, strempty(initrd), initrd ? "\"" : "");
-        if (arg_dry_run)
-                return 0;
-
-        r = safe_fork("(kexec)", FORK_WAIT|FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
-        if (r < 0)
-                return r;
-        if (r == 0) {
-                const char* const args[] = {
-                        KEXEC,
-                        "--load", kernel,
-                        "--append", options,
-                        initrd ? "--initrd" : NULL, initrd,
-                        NULL
-                };
-
-                /* Child */
-                execv(args[0], (char * const *) args);
-                _exit(EXIT_FAILURE);
-        }
-
-        return 0;
-}
-
-static int set_exit_code(uint8_t code) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_call_method(bus, bus_systemd_mgr, "SetExitCode", &error, NULL, "y", code);
-        if (r < 0)
-                return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
-
-        return 0;
-}
-
-static int start_special(int argc, char *argv[], void *userdata) {
-        enum action a;
-        int r;
-        bool termination_action; /* an action that terminates the manager,
-                                  * can be performed also by signal. */
-
-        assert(argv);
-
-        a = verb_to_action(argv[0]);
-
-        r = logind_check_inhibitors(a);
-        if (r < 0)
-                return r;
-
-        if (arg_force >= 2) {
-                r = must_be_root();
-                if (r < 0)
-                        return r;
-        }
-
-        r = prepare_firmware_setup();
-        if (r < 0)
-                return r;
-
-        r = prepare_boot_loader_menu();
-        if (r < 0)
-                return r;
-
-        r = prepare_boot_loader_entry();
-        if (r < 0)
-                return r;
-
-        if (a == ACTION_REBOOT) {
-                const char *arg = NULL;
-
-                if (argc > 1) {
-                        if (arg_reboot_argument)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Both --reboot-argument= and positional argument passed to reboot command, refusing.");
-
-                        log_notice("Positional argument to reboot command is deprecated, please use --reboot-argument= instead. Accepting anyway.");
-                        arg = argv[1];
-                } else
-                        arg = arg_reboot_argument;
-
-                if (arg) {
-                        r = update_reboot_parameter_and_warn(arg, false);
-                        if (r < 0)
-                                return r;
-                }
-
-        } else if (a == ACTION_KEXEC) {
-                r = load_kexec_kernel();
-                if (r < 0 && arg_force >= 1)
-                        log_notice("Failed to load kexec kernel, continuing without.");
-                else if (r < 0)
-                        return r;
-
-        } else if (a == ACTION_EXIT && argc > 1) {
-                uint8_t code;
-
-                /* If the exit code is not given on the command line,
-                 * don't reset it to zero: just keep it as it might
-                 * have been set previously. */
-
-                r = safe_atou8(argv[1], &code);
-                if (r < 0)
-                        return log_error_errno(r, "Invalid exit code.");
-
-                r = set_exit_code(code);
-                if (r < 0)
-                        return r;
-        }
-
-        termination_action = IN_SET(a,
-                                    ACTION_HALT,
-                                    ACTION_POWEROFF,
-                                    ACTION_REBOOT);
-        if (termination_action && arg_force >= 2)
-                return halt_now(a);
-
-        if (arg_force >= 1 &&
-            (termination_action || IN_SET(a, ACTION_KEXEC, ACTION_EXIT)))
-                r = trivial_method(argc, argv, userdata);
-        else {
-                /* First try logind, to allow authentication with polkit */
-                if (IN_SET(a,
-                           ACTION_POWEROFF,
-                           ACTION_REBOOT,
-                           ACTION_HALT,
-                           ACTION_SUSPEND,
-                           ACTION_HIBERNATE,
-                           ACTION_HYBRID_SLEEP,
-                           ACTION_SUSPEND_THEN_HIBERNATE)) {
-
-                        r = logind_reboot(a);
-                        if (r >= 0)
-                                return r;
-                        if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
-                                /* requested operation is not supported or already in progress */
-                                return r;
-
-                        /* On all other errors, try low-level operation. In order to minimize the difference between
-                         * operation with and without logind, we explicitly enable non-blocking mode for this, as
-                         * logind's shutdown operations are always non-blocking. */
-
-                        arg_no_block = true;
-
-                } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
-                        /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make them
-                         * asynchronous, in order to not confuse the user needlessly with unexpected behaviour. */
-                        arg_no_block = true;
-
-                r = start_unit(argc, argv, userdata);
-        }
-
-        if (termination_action && arg_force < 2 &&
-            IN_SET(r, -ENOENT, -ETIMEDOUT))
-                log_notice("It is possible to perform action directly, see discussion of --force --force in man:systemctl(1).");
-
-        return r;
-}
-
-static int start_system_special(int argc, char *argv[], void *userdata) {
-        /* Like start_special above, but raises an error when running in user mode */
-
-        if (arg_scope != UNIT_FILE_SYSTEM)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Bad action for %s mode.",
-                                       arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
-
-        return start_special(argc, argv, userdata);
-}
-
-static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
-        _cleanup_strv_free_ char **names = NULL;
-        UnitActiveState active_state;
-        sd_bus *bus;
-        char **name;
-        int r, i;
-        bool found = false;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = expand_names(bus, args, NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        STRV_FOREACH(name, names) {
-                r = get_state_one_unit(bus, *name, &active_state);
-                if (r < 0)
-                        return r;
-
-                if (!arg_quiet)
-                        puts(unit_active_state_to_string(active_state));
-
-                for (i = 0; i < nb_states; ++i)
-                        if (good_states[i] == active_state)
-                                found = true;
-        }
-
-        /* use the given return code for the case that we won't find
-         * any unit which matches the list */
-        return found ? 0 : code;
-}
-
-static int check_unit_active(int argc, char *argv[], void *userdata) {
-        static const UnitActiveState states[] = {
-                UNIT_ACTIVE,
-                UNIT_RELOADING,
-        };
-
-        /* According to LSB: 3, "program is not running" */
-        return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
-}
-
-static int check_unit_failed(int argc, char *argv[], void *userdata) {
-        static const UnitActiveState states[] = {
-                UNIT_FAILED,
-        };
-
-        return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
-}
-
-static int kill_unit(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        char *kill_who = NULL, **name;
-        sd_bus *bus;
-        int r, q;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        if (!arg_kill_who)
-                arg_kill_who = "all";
-
-        /* --fail was specified */
-        if (streq(arg_job_mode, "fail"))
-                kill_who = strjoina(arg_kill_who, "-fail");
-
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        STRV_FOREACH(name, names) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
-                q = bus_call_method(
-                                bus,
-                                bus_systemd_mgr,
-                                "KillUnit",
-                                &error,
-                                NULL,
-                                "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
-                if (q < 0) {
-                        log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
-                        if (r == 0)
-                                r = q;
-                }
-        }
-
-        return r;
-}
-
-static int clean_or_freeze_unit(int argc, char *argv[], void *userdata) {
-        _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
-        _cleanup_strv_free_ char **names = NULL;
-        int r, ret = EXIT_SUCCESS;
-        char **name;
-        const char *method;
-        sd_bus *bus;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        if (!arg_clean_what) {
-                arg_clean_what = strv_new("cache", "runtime");
-                if (!arg_clean_what)
-                        return log_oom();
-        }
-
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        if (!arg_no_block) {
-                r = bus_wait_for_units_new(bus, &w);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to allocate unit waiter: %m");
-        }
-
-        if (streq(argv[0], "clean"))
-                method = "CleanUnit";
-        else if (streq(argv[0], "freeze"))
-                method = "FreezeUnit";
-        else if (streq(argv[0], "thaw"))
-                method = "ThawUnit";
-        else
-                assert_not_reached("Unhandled method");
-
-        STRV_FOREACH(name, names) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-
-                if (w) {
-                        /* If we shall wait for the cleaning to complete, let's add a ref on the unit first */
-                        r = bus_call_method(bus, bus_systemd_mgr, "RefUnit", &error, NULL, "s", *name);
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r));
-                                if (ret == EXIT_SUCCESS)
-                                        ret = r;
-                                continue;
-                        }
-                }
-
-                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append(m, "s", *name);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                if (streq(method, "CleanUnit")) {
-                        r = sd_bus_message_append_strv(m, arg_clean_what);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_call(bus, m, 0, &error, NULL);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to %s unit %s: %s", argv[0], *name, bus_error_message(&error, r));
-                        if (ret == EXIT_SUCCESS) {
-                                ret = r;
-                                continue;
-                        }
-                }
-
-                if (w) {
-                        r = bus_wait_for_units_add_unit(w, *name, BUS_WAIT_REFFED|BUS_WAIT_FOR_MAINTENANCE_END, NULL, NULL);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to watch unit %s: %m", *name);
-                }
-        }
-
-        r = bus_wait_for_units_run(w);
-        if (r < 0)
-                return log_error_errno(r, "Failed to wait for units: %m");
-        if (r == BUS_WAIT_FAILURE)
-                ret = EXIT_FAILURE;
-
-        return ret;
-}
-
-typedef struct ExecStatusInfo {
-        char *name;
-
-        char *path;
-        char **argv;
-
-        bool ignore;
-
-        usec_t start_timestamp;
-        usec_t exit_timestamp;
-        pid_t pid;
-        int code;
-        int status;
-
-        ExecCommandFlags flags;
-
-        LIST_FIELDS(struct ExecStatusInfo, exec);
-} ExecStatusInfo;
-
-static void exec_status_info_free(ExecStatusInfo *i) {
-        assert(i);
-
-        free(i->name);
-        free(i->path);
-        strv_free(i->argv);
-        free(i);
-}
-
-static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i, bool is_ex_prop) {
-        _cleanup_strv_free_ char **ex_opts = NULL;
-        uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
-        const char *path;
-        uint32_t pid;
-        int32_t code, status;
-        int ignore, r;
-
-        assert(m);
-        assert(i);
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, is_ex_prop ? "sasasttttuii" : "sasbttttuii");
-        if (r < 0)
-                return bus_log_parse_error(r);
-        else if (r == 0)
-                return 0;
-
-        r = sd_bus_message_read(m, "s", &path);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        i->path = strdup(path);
-        if (!i->path)
-                return log_oom();
-
-        r = sd_bus_message_read_strv(m, &i->argv);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = is_ex_prop ? sd_bus_message_read_strv(m, &ex_opts) : sd_bus_message_read(m, "b", &ignore);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_read(m,
-                                "ttttuii",
-                                &start_timestamp, &start_timestamp_monotonic,
-                                &exit_timestamp, &exit_timestamp_monotonic,
-                                &pid,
-                                &code, &status);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        if (is_ex_prop) {
-                r = exec_command_flags_from_strv(ex_opts, &i->flags);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to convert strv to ExecCommandFlags: %m");
-
-                i->ignore = FLAGS_SET(i->flags, EXEC_COMMAND_IGNORE_FAILURE);
-        } else
-                i->ignore = ignore;
-
-        i->start_timestamp = (usec_t) start_timestamp;
-        i->exit_timestamp = (usec_t) exit_timestamp;
-        i->pid = (pid_t) pid;
-        i->code = code;
-        i->status = status;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return 1;
-}
-
-typedef struct UnitCondition {
-        char *name;
-        char *param;
-        bool trigger;
-        bool negate;
-        int tristate;
-
-        LIST_FIELDS(struct UnitCondition, conditions);
-} UnitCondition;
-
-static void unit_condition_free(UnitCondition *c) {
-        if (!c)
-                return;
-
-        free(c->name);
-        free(c->param);
-        free(c);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
-
-typedef struct UnitStatusInfo {
-        const char *id;
-        const char *load_state;
-        const char *active_state;
-        const char *freezer_state;
-        const char *sub_state;
-        const char *unit_file_state;
-        const char *unit_file_preset;
-
-        const char *description;
-        const char *following;
-
-        char **documentation;
-
-        const char *fragment_path;
-        const char *source_path;
-        const char *control_group;
-
-        char **dropin_paths;
-
-        char **triggered_by;
-        char **triggers;
-
-        const char *load_error;
-        const char *result;
-
-        usec_t inactive_exit_timestamp;
-        usec_t inactive_exit_timestamp_monotonic;
-        usec_t active_enter_timestamp;
-        usec_t active_exit_timestamp;
-        usec_t inactive_enter_timestamp;
-
-        bool need_daemon_reload;
-        bool transient;
-
-        /* Service */
-        pid_t main_pid;
-        pid_t control_pid;
-        const char *status_text;
-        const char *pid_file;
-        bool running:1;
-        int status_errno;
-
-        usec_t start_timestamp;
-        usec_t exit_timestamp;
-
-        int exit_code, exit_status;
-
-        const char *log_namespace;
-
-        usec_t condition_timestamp;
-        bool condition_result;
-        LIST_HEAD(UnitCondition, conditions);
-
-        usec_t assert_timestamp;
-        bool assert_result;
-        bool failed_assert_trigger;
-        bool failed_assert_negate;
-        const char *failed_assert;
-        const char *failed_assert_parameter;
-        usec_t next_elapse_real;
-        usec_t next_elapse_monotonic;
-
-        /* Socket */
-        unsigned n_accepted;
-        unsigned n_connections;
-        unsigned n_refused;
-        bool accept;
-
-        /* Pairs of type, path */
-        char **listen;
-
-        /* Device */
-        const char *sysfs_path;
-
-        /* Mount, Automount */
-        const char *where;
-
-        /* Swap */
-        const char *what;
-
-        /* CGroup */
-        uint64_t memory_current;
-        uint64_t memory_min;
-        uint64_t memory_low;
-        uint64_t memory_high;
-        uint64_t memory_max;
-        uint64_t memory_swap_max;
-        uint64_t memory_limit;
-        uint64_t cpu_usage_nsec;
-        uint64_t tasks_current;
-        uint64_t tasks_max;
-        uint64_t ip_ingress_bytes;
-        uint64_t ip_egress_bytes;
-        uint64_t io_read_bytes;
-        uint64_t io_write_bytes;
-
-        uint64_t default_memory_min;
-        uint64_t default_memory_low;
-
-        LIST_HEAD(ExecStatusInfo, exec);
-} UnitStatusInfo;
-
-static void unit_status_info_free(UnitStatusInfo *info) {
-        ExecStatusInfo *p;
-        UnitCondition *c;
-
-        strv_free(info->documentation);
-        strv_free(info->dropin_paths);
-        strv_free(info->triggered_by);
-        strv_free(info->triggers);
-        strv_free(info->listen);
-
-        while ((c = info->conditions)) {
-                LIST_REMOVE(conditions, info->conditions, c);
-                unit_condition_free(c);
-        }
-
-        while ((p = info->exec)) {
-                LIST_REMOVE(exec, info->exec, p);
-                exec_status_info_free(p);
-        }
-}
-
-static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
-        if (streq_ptr(active_state, "failed")) {
-                *active_on = ansi_highlight_red();
-                *active_off = ansi_normal();
-        } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
-                *active_on = ansi_highlight_green();
-                *active_off = ansi_normal();
-        } else
-                *active_on = *active_off = "";
-}
-
-static void print_status_info(
-                sd_bus *bus,
-                UnitStatusInfo *i,
-                bool *ellipsized) {
-
-        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
-        const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
-        _cleanup_free_ char *formatted_path = NULL;
-        ExecStatusInfo *p;
-        usec_t timestamp;
-        const char *path;
-        char **t, **t2;
-        int r;
-
-        assert(i);
-
-        /* This shows pretty information about a unit. See
-         * print_property() for a low-level property printer */
-
-        format_active_state(i->active_state, &active_on, &active_off);
-
-        printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id));
-
-        if (i->description && !streq_ptr(i->id, i->description))
-                printf(" - %s", i->description);
-
-        printf("\n");
-
-        if (i->following)
-                printf("   Follow: unit currently follows state of %s\n", i->following);
-
-        if (STRPTR_IN_SET(i->load_state, "error", "not-found", "bad-setting")) {
-                on = ansi_highlight_red();
-                off = ansi_normal();
-        } else
-                on = off = "";
-
-        path = i->source_path ?: i->fragment_path;
-        if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
-                path = formatted_path;
-
-        if (!isempty(i->load_error))
-                printf("     Loaded: %s%s%s (Reason: %s)\n",
-                       on, strna(i->load_state), off, i->load_error);
-        else if (path && !isempty(i->unit_file_state)) {
-                bool show_preset = !isempty(i->unit_file_preset) &&
-                        show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
-
-                printf("     Loaded: %s%s%s (%s; %s%s%s)\n",
-                       on, strna(i->load_state), off,
-                       path,
-                       i->unit_file_state,
-                       show_preset ? "; vendor preset: " : "",
-                       show_preset ? i->unit_file_preset : "");
-
-        } else if (path)
-                printf("     Loaded: %s%s%s (%s)\n",
-                       on, strna(i->load_state), off, path);
-        else
-                printf("     Loaded: %s%s%s\n",
-                       on, strna(i->load_state), off);
-
-        if (i->transient)
-                printf("  Transient: yes\n");
-
-        if (!strv_isempty(i->dropin_paths)) {
-                _cleanup_free_ char *dir = NULL;
-                bool last = false;
-                char ** dropin;
-
-                STRV_FOREACH(dropin, i->dropin_paths) {
-                        _cleanup_free_ char *dropin_formatted = NULL;
-                        const char *df;
-
-                        if (!dir || last) {
-                                printf(dir ? "             " :
-                                             "    Drop-In: ");
-
-                                dir = mfree(dir);
-
-                                dir = dirname_malloc(*dropin);
-                                if (!dir) {
-                                        log_oom();
-                                        return;
-                                }
-
-                                printf("%s\n"
-                                       "             %s", dir,
-                                       special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
-                        }
-
-                        last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
-
-                        if (terminal_urlify_path(*dropin, basename(*dropin), &dropin_formatted) >= 0)
-                                df = dropin_formatted;
-                        else
-                                df = *dropin;
-
-                        printf("%s%s", df, last ? "\n" : ", ");
-                }
-        }
-
-        ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
-        if (ss)
-                printf("     Active: %s%s (%s)%s",
-                       active_on, strna(i->active_state), ss, active_off);
-        else
-                printf("     Active: %s%s%s",
-                       active_on, strna(i->active_state), active_off);
-
-        fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
-        if (fs)
-                printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
-
-        if (!isempty(i->result) && !streq(i->result, "success"))
-                printf(" (Result: %s)", i->result);
-
-        timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
-                    STRPTR_IN_SET(i->active_state, "inactive", "failed")  ? i->inactive_enter_timestamp :
-                    STRPTR_IN_SET(i->active_state, "activating")          ? i->inactive_exit_timestamp :
-                                                                            i->active_exit_timestamp;
-
-        s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
-        s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
-
-        if (s1)
-                printf(" since %s; %s\n", s2, s1);
-        else if (s2)
-                printf(" since %s\n", s2);
-        else
-                printf("\n");
-
-        STRV_FOREACH(t, i->triggered_by) {
-                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
-
-                (void) get_state_one_unit(bus, *t, &state);
-                format_active_state(unit_active_state_to_string(state), &on, &off);
-
-                printf("%s %s%s%s %s\n",
-                       t == i->triggered_by ? "TriggeredBy:" : "            ",
-                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
-                       *t);
-        }
-
-        if (endswith(i->id, ".timer")) {
-                char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
-                     tstamp2[FORMAT_TIMESTAMP_MAX];
-                const char *next_rel_time, *next_time;
-                dual_timestamp nw, next = {i->next_elapse_real,
-                                           i->next_elapse_monotonic};
-                usec_t next_elapse;
-
-                printf("    Trigger: ");
-
-                dual_timestamp_get(&nw);
-                next_elapse = calc_next_elapse(&nw, &next);
-                next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
-                next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
-
-                if (next_time && next_rel_time)
-                        printf("%s; %s\n", next_time, next_rel_time);
-                else
-                        printf("n/a\n");
-        }
-
-        STRV_FOREACH(t, i->triggers) {
-                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
-
-                (void) get_state_one_unit(bus, *t, &state);
-                format_active_state(unit_active_state_to_string(state), &on, &off);
-
-                printf("%s %s%s%s %s\n",
-                       t == i->triggers ? "   Triggers:" : "            ",
-                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
-                       *t);
-        }
-
-        if (!i->condition_result && i->condition_timestamp > 0) {
-                UnitCondition *c;
-                int n = 0;
-
-                s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
-                s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
-
-                printf("  Condition: start %scondition failed%s at %s%s%s\n",
-                       ansi_highlight_yellow(), ansi_normal(),
-                       s2, s1 ? "; " : "", strempty(s1));
-
-                LIST_FOREACH(conditions, c, i->conditions)
-                        if (c->tristate < 0)
-                                n++;
-
-                LIST_FOREACH(conditions, c, i->conditions)
-                        if (c->tristate < 0)
-                                printf("             %s %s=%s%s%s was not met\n",
-                                       --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
-                                       c->name,
-                                       c->trigger ? "|" : "",
-                                       c->negate ? "!" : "",
-                                       c->param);
-        }
-
-        if (!i->assert_result && i->assert_timestamp > 0) {
-                s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
-                s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
-
-                printf("     Assert: start %sassertion failed%s at %s%s%s\n",
-                       ansi_highlight_red(), ansi_normal(),
-                       s2, s1 ? "; " : "", strempty(s1));
-                if (i->failed_assert_trigger)
-                        printf("             none of the trigger assertions were met\n");
-                else if (i->failed_assert)
-                        printf("             %s=%s%s was not met\n",
-                               i->failed_assert,
-                               i->failed_assert_negate ? "!" : "",
-                               i->failed_assert_parameter);
-        }
-
-        if (i->sysfs_path)
-                printf("     Device: %s\n", i->sysfs_path);
-        if (i->where)
-                printf("      Where: %s\n", i->where);
-        if (i->what)
-                printf("       What: %s\n", i->what);
-
-        STRV_FOREACH(t, i->documentation) {
-                _cleanup_free_ char *formatted = NULL;
-                const char *q;
-
-                if (terminal_urlify(*t, NULL, &formatted) >= 0)
-                        q = formatted;
-                else
-                        q = *t;
-
-                printf("   %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
-        }
-
-        STRV_FOREACH_PAIR(t, t2, i->listen)
-                printf("   %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
-
-        if (i->accept) {
-                printf("   Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
-                if (i->n_refused)
-                        printf("   Refused: %u", i->n_refused);
-                printf("\n");
-        }
-
-        LIST_FOREACH(exec, p, i->exec) {
-                _cleanup_free_ char *argv = NULL;
-                bool good;
-
-                /* Only show exited processes here */
-                if (p->code == 0)
-                        continue;
-
-                /* Don't print ExecXYZEx= properties here since it will appear as a
-                 * duplicate of the non-Ex= variant. */
-                if (endswith(p->name, "Ex"))
-                        continue;
-
-                argv = strv_join(p->argv, " ");
-                printf("    Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
-
-                good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
-                if (!good) {
-                        on = ansi_highlight_red();
-                        off = ansi_normal();
-                } else
-                        on = off = "";
-
-                printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
-
-                if (p->code == CLD_EXITED) {
-                        const char *c;
-
-                        printf("status=%i", p->status);
-
-                        c = exit_status_to_string(p->status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
-                        if (c)
-                                printf("/%s", c);
-
-                } else
-                        printf("signal=%s", signal_to_string(p->status));
-
-                printf(")%s\n", off);
-
-                if (i->main_pid == p->pid &&
-                    i->start_timestamp == p->start_timestamp &&
-                    i->exit_timestamp == p->start_timestamp)
-                        /* Let's not show this twice */
-                        i->main_pid = 0;
-
-                if (p->pid == i->control_pid)
-                        i->control_pid = 0;
-        }
-
-        if (i->main_pid > 0 || i->control_pid > 0) {
-                if (i->main_pid > 0) {
-                        printf("   Main PID: "PID_FMT, i->main_pid);
-
-                        if (i->running) {
-
-                                if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                                        _cleanup_free_ char *comm = NULL;
-
-                                        (void) get_process_comm(i->main_pid, &comm);
-                                        if (comm)
-                                                printf(" (%s)", comm);
-                                }
-
-                        } else if (i->exit_code > 0) {
-                                printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
-
-                                if (i->exit_code == CLD_EXITED) {
-                                        const char *c;
-
-                                        printf("status=%i", i->exit_status);
-
-                                        c = exit_status_to_string(i->exit_status,
-                                                                  EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
-                                        if (c)
-                                                printf("/%s", c);
-
-                                } else
-                                        printf("signal=%s", signal_to_string(i->exit_status));
-                                printf(")");
-                        }
-                }
-
-                if (i->control_pid > 0) {
-                        _cleanup_free_ char *c = NULL;
-
-                        if (i->main_pid > 0)
-                                fputs("; Control PID: ", stdout);
-                        else
-                                fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
-
-                        printf(PID_FMT, i->control_pid);
-
-                        if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                                (void) get_process_comm(i->control_pid, &c);
-                                if (c)
-                                        printf(" (%s)", c);
-                        }
-                }
-
-                printf("\n");
-        }
-
-        if (i->status_text)
-                printf("     Status: \"%s\"\n", i->status_text);
-        if (i->status_errno > 0)
-                printf("      Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
-
-        if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
-                char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
-
-                printf("         IP: %s in, %s out\n",
-                        format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
-                        format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
-        }
-
-        if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
-                char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
-
-                printf("         IO: %s read, %s written\n",
-                        format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
-                        format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
-        }
-
-        if (i->tasks_current != (uint64_t) -1) {
-                printf("      Tasks: %" PRIu64, i->tasks_current);
-
-                if (i->tasks_max != (uint64_t) -1)
-                        printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
-                else
-                        printf("\n");
-        }
-
-        if (i->memory_current != (uint64_t) -1) {
-                char buf[FORMAT_BYTES_MAX];
-
-                printf("     Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
-
-                if (i->memory_min > 0 || i->memory_low > 0 ||
-                    i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
-                    i->memory_swap_max != CGROUP_LIMIT_MAX ||
-                    i->memory_limit != CGROUP_LIMIT_MAX) {
-                        const char *prefix = "";
-
-                        printf(" (");
-                        if (i->memory_min > 0) {
-                                printf("%smin: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_min));
-                                prefix = " ";
-                        }
-                        if (i->memory_low > 0) {
-                                printf("%slow: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_low));
-                                prefix = " ";
-                        }
-                        if (i->memory_high != CGROUP_LIMIT_MAX) {
-                                printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
-                                prefix = " ";
-                        }
-                        if (i->memory_max != CGROUP_LIMIT_MAX) {
-                                printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
-                                prefix = " ";
-                        }
-                        if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
-                                printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
-                                prefix = " ";
-                        }
-                        if (i->memory_limit != CGROUP_LIMIT_MAX) {
-                                printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
-                                prefix = " ";
-                        }
-                        printf(")");
-                }
-                printf("\n");
-        }
-
-        if (i->cpu_usage_nsec != (uint64_t) -1) {
-                char buf[FORMAT_TIMESPAN_MAX];
-                printf("        CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
-        }
-
-        if (i->control_group) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                static const char prefix[] = "             ";
-                unsigned c;
-
-                printf("     CGroup: %s\n", i->control_group);
-
-                c = columns();
-                if (c > sizeof(prefix) - 1)
-                        c -= sizeof(prefix) - 1;
-                else
-                        c = 0;
-
-                r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
-                if (r == -EBADR) {
-                        unsigned k = 0;
-                        pid_t extra[2];
-
-                        /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
-
-                        if (i->main_pid > 0)
-                                extra[k++] = i->main_pid;
-
-                        if (i->control_pid > 0)
-                                extra[k++] = i->control_pid;
-
-                        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
-                } else if (r < 0)
-                        log_warning_errno(r, "Failed to dump process list for '%s', ignoring: %s",
-                                          i->id, bus_error_message(&error, r));
-        }
-
-        if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
-                show_journal_by_unit(
-                                stdout,
-                                i->id,
-                                i->log_namespace,
-                                arg_output,
-                                0,
-                                i->inactive_exit_timestamp_monotonic,
-                                arg_lines,
-                                getuid(),
-                                get_output_flags() | OUTPUT_BEGIN_NEWLINE,
-                                SD_JOURNAL_LOCAL_ONLY,
-                                arg_scope == UNIT_FILE_SYSTEM,
-                                ellipsized);
-
-        if (i->need_daemon_reload)
-                warn_unit_file_changed(i->id);
-}
-
-static void show_unit_help(UnitStatusInfo *i) {
-        char **p;
-
-        assert(i);
-
-        if (!i->documentation) {
-                log_info("Documentation for %s not known.", i->id);
-                return;
-        }
-
-        STRV_FOREACH(p, i->documentation)
-                if (startswith(*p, "man:"))
-                        show_man_page(*p + 4, false);
-                else
-                        log_info("Can't show: %s", *p);
-}
-
-static int map_main_pid(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        UnitStatusInfo *i = userdata;
-        uint32_t u;
-        int r;
-
-        r = sd_bus_message_read(m, "u", &u);
-        if (r < 0)
-                return r;
-
-        i->main_pid = (pid_t) u;
-        i->running = u > 0;
-
-        return 0;
-}
-
-static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        const char *message, **p = userdata;
-        int r;
-
-        r = sd_bus_message_read(m, "(ss)", NULL, &message);
-        if (r < 0)
-                return r;
-
-        if (!isempty(message))
-                *p = message;
-
-        return 0;
-}
-
-static int map_listen(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        const char *type, *path;
-        char ***p = userdata;
-        int r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
-        if (r < 0)
-                return r;
-
-        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
-
-                r = strv_extend(p, type);
-                if (r < 0)
-                        return r;
-
-                r = strv_extend(p, path);
-                if (r < 0)
-                        return r;
-        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        UnitStatusInfo *i = userdata;
-        const char *cond, *param;
-        int trigger, negate;
-        int32_t state;
-        int r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
-        if (r < 0)
-                return r;
-
-        while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
-                _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
-
-                c = new(UnitCondition, 1);
-                if (!c)
-                        return -ENOMEM;
-
-                *c = (UnitCondition) {
-                        .name = strdup(cond),
-                        .param = strdup(param),
-                        .trigger = trigger,
-                        .negate = negate,
-                        .tristate = state,
-                };
-
-                if (!c->name || !c->param)
-                        return -ENOMEM;
-
-                LIST_PREPEND(conditions, i->conditions, TAKE_PTR(c));
-        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int map_asserts(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        UnitStatusInfo *i = userdata;
-        const char *cond, *param;
-        int trigger, negate;
-        int32_t state;
-        int r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
-        if (r < 0)
-                return r;
-
-        while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
-                if (state < 0 && (!trigger || !i->failed_assert)) {
-                        i->failed_assert = cond;
-                        i->failed_assert_trigger = trigger;
-                        i->failed_assert_negate = negate;
-                        i->failed_assert_parameter = param;
-                }
-        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        _cleanup_free_ ExecStatusInfo *info = NULL;
-        ExecStatusInfo *last;
-        UnitStatusInfo *i = userdata;
-        bool is_ex_prop = endswith(member, "Ex");
-        int r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
-        if (r < 0)
-                return r;
-
-        info = new0(ExecStatusInfo, 1);
-        if (!info)
-                return -ENOMEM;
-
-        LIST_FIND_TAIL(exec, i->exec, last);
-
-        while ((r = exec_status_info_deserialize(m, info, is_ex_prop)) > 0) {
-
-                info->name = strdup(member);
-                if (!info->name)
-                        return -ENOMEM;
-
-                LIST_INSERT_AFTER(exec, i->exec, last, info);
-                last = info;
-
-                info = new0(ExecStatusInfo, 1);
-                if (!info)
-                        return -ENOMEM;
-        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
-        char bus_type;
-        const char *contents;
-        int r;
-
-        assert(name);
-        assert(m);
-
-        /* This is a low-level property printer, see
-         * print_status_info() for the nicer output */
-
-        r = sd_bus_message_peek_type(m, &bus_type, &contents);
-        if (r < 0)
-                return r;
-
-        switch (bus_type) {
-
-        case SD_BUS_TYPE_INT32:
-                if (endswith(name, "ActionExitStatus")) {
-                        int32_t i;
-
-                        r = sd_bus_message_read_basic(m, bus_type, &i);
-                        if (r < 0)
-                                return r;
-
-                        if (i >= 0 && i <= 255)
-                                bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
-                        else if (all)
-                                bus_print_property_value(name, expected_value, value, "[not set]");
-
-                        return 1;
-                } else if (streq(name, "NUMAPolicy")) {
-                        int32_t i;
-
-                        r = sd_bus_message_read_basic(m, bus_type, &i);
-                        if (r < 0)
-                                return r;
-
-                        bus_print_property_valuef(name, expected_value, value, "%s", strna(mpol_to_string(i)));
-
-                        return 1;
-                }
-                break;
-
-        case SD_BUS_TYPE_STRUCT:
-
-                if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
-                        uint32_t u;
-
-                        r = sd_bus_message_read(m, "(uo)", &u, NULL);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (u > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
-                        else if (all)
-                                bus_print_property_value(name, expected_value, value, "");
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
-                        const char *s;
-
-                        r = sd_bus_message_read(m, "(so)", &s, NULL);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (all || !isempty(s))
-                                bus_print_property_value(name, expected_value, value, s);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
-                        const char *a = NULL, *b = NULL;
-
-                        r = sd_bus_message_read(m, "(ss)", &a, &b);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (!isempty(a) || !isempty(b))
-                                bus_print_property_valuef(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
-                        else if (all)
-                                bus_print_property_value(name, expected_value, value, "");
-
-                        return 1;
-
-                } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies")) {
-                        _cleanup_strv_free_ char **l = NULL;
-                        int allow_list;
-
-                        r = sd_bus_message_enter_container(m, 'r', "bas");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        r = sd_bus_message_read(m, "b", &allow_list);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        r = sd_bus_message_read_strv(m, &l);
-                        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 (all || allow_list || !strv_isempty(l)) {
-                                bool first = true;
-                                char **i;
-
-                                if (!value) {
-                                        fputs(name, stdout);
-                                        fputc('=', stdout);
-                                }
-
-                                if (!allow_list)
-                                        fputc('~', stdout);
-
-                                STRV_FOREACH(i, l) {
-                                        if (first)
-                                                first = false;
-                                        else
-                                                fputc(' ', stdout);
-
-                                        fputs(*i, stdout);
-                                }
-                                fputc('\n', stdout);
-                        }
-
-                        return 1;
-
-                } else if (STR_IN_SET(name, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
-                        int ignore;
-                        const char *s;
-
-                        r = sd_bus_message_read(m, "(bs)", &ignore, &s);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (!isempty(s))
-                                bus_print_property_valuef(name, expected_value, value, "%s%s", ignore ? "-" : "", s);
-                        else if (all)
-                                bus_print_property_value(name, expected_value, value, "");
-
-                        return 1;
-
-                } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
-                        const int32_t *status, *signal;
-                        size_t n_status, n_signal, i;
-
-                        r = sd_bus_message_enter_container(m, 'r', "aiai");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        r = sd_bus_message_read_array(m, 'i', (const void **) &status, &n_status);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        r = sd_bus_message_read_array(m, 'i', (const void **) &signal, &n_signal);
-                        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);
-
-                        n_status /= sizeof(int32_t);
-                        n_signal /= sizeof(int32_t);
-
-                        if (all || n_status > 0 || n_signal > 0) {
-                                bool first = true;
-
-                                if (!value) {
-                                        fputs(name, stdout);
-                                        fputc('=', stdout);
-                                }
-
-                                for (i = 0; i < n_status; i++) {
-                                        if (first)
-                                                first = false;
-                                        else
-                                                fputc(' ', stdout);
-
-                                        printf("%"PRIi32, status[i]);
-                                }
-
-                                for (i = 0; i < n_signal; i++) {
-                                        const char *str;
-
-                                        str = signal_to_string((int) signal[i]);
-
-                                        if (first)
-                                                first = false;
-                                        else
-                                                fputc(' ', stdout);
-
-                                        if (str)
-                                                fputs(str, stdout);
-                                        else
-                                                printf("%"PRIi32, status[i]);
-                                }
-
-                                fputc('\n', stdout);
-                        }
-                        return 1;
-                }
-
-                break;
-
-        case SD_BUS_TYPE_ARRAY:
-
-                if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
-                        const char *path;
-                        int ignore;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
-
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
-                        const char *type, *path;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
-                        const char *type, *path;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
-                        const char *base;
-                        uint64_t v, next_elapse;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
-                                char timespan1[FORMAT_TIMESPAN_MAX] = "n/a", timespan2[FORMAT_TIMESPAN_MAX] = "n/a";
-
-                                (void) format_timespan(timespan1, sizeof timespan1, v, 0);
-                                (void) format_timespan(timespan2, sizeof timespan2, next_elapse, 0);
-
-                                bus_print_property_valuef(name, expected_value, value,
-                                                          "{ %s=%s ; next_elapse=%s }", base, timespan1, timespan2);
-                        }
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
-                        const char *base, *spec;
-                        uint64_t next_elapse;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
-                                char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
-
-                                (void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
-                                bus_print_property_valuef(name, expected_value, value,
-                                                          "{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
-                        }
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
-                        ExecStatusInfo info = {};
-                        bool is_ex_prop = endswith(name, "Ex");
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
-                                char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
-                                _cleanup_strv_free_ char **optv = NULL;
-                                _cleanup_free_ char *tt, *o = NULL;
-
-                                tt = strv_join(info.argv, " ");
-
-                                if (is_ex_prop) {
-                                        r = exec_command_flags_to_strv(info.flags, &optv);
-                                        if (r < 0)
-                                                return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
-
-                                        o = strv_join(optv, " ");
-
-                                        bus_print_property_valuef(name, expected_value, value,
-                                                                  "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
-                                                                  strna(info.path),
-                                                                  strna(tt),
-                                                                  strna(o),
-                                                                  strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
-                                                                  strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
-                                                                  info.pid,
-                                                                  sigchld_code_to_string(info.code),
-                                                                  info.status,
-                                                                  info.code == CLD_EXITED ? "" : "/",
-                                                                  strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
-                                } else
-                                        bus_print_property_valuef(name, expected_value, value,
-                                                                  "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
-                                                                  strna(info.path),
-                                                                  strna(tt),
-                                                                  yes_no(info.ignore),
-                                                                  strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
-                                                                  strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
-                                                                  info.pid,
-                                                                  sigchld_code_to_string(info.code),
-                                                                  info.status,
-                                                                  info.code == CLD_EXITED ? "" : "/",
-                                                                  strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
-
-                                free(info.path);
-                                strv_free(info.argv);
-                                zero(info);
-                        }
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
-                        const char *path, *rwm;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path), strna(rwm));
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
-                           STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
-                        const char *path;
-                        uint64_t weight;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
-                           (cgroup_io_limit_type_from_string(name) >= 0 ||
-                            STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
-                        const char *path;
-                        uint64_t bandwidth;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
-                        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);
-
-                        return 1;
-
-                }  else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
-                            streq(name, "IODeviceLatencyTargetUSec")) {
-                        char ts[FORMAT_TIMESPAN_MAX];
-                        const char *path;
-                        uint64_t target;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
-                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path),
-                                                          format_timespan(ts, sizeof(ts), target, 1));
-                        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);
-
-                        return 1;
-
-                } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "StandardInputData", "RootHashSignature")) {
-                        _cleanup_free_ char *h = NULL;
-                        const void *p;
-                        size_t sz;
-                        ssize_t n;
-
-                        r = sd_bus_message_read_array(m, 'y', &p, &sz);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        n = base64mem(p, sz, &h);
-                        if (n < 0)
-                                return log_oom();
-
-                        bus_print_property_value(name, expected_value, value, h);
-
-                        return 1;
-
-                } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
-                        _cleanup_free_ char *addresses = NULL;
-
-                        r = sd_bus_message_enter_container(m, 'a', "(iayu)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        for (;;) {
-                                _cleanup_free_ char *str = NULL;
-                                uint32_t prefixlen;
-                                int32_t family;
-                                const void *ap;
-                                size_t an;
-
-                                r = sd_bus_message_enter_container(m, 'r', "iayu");
-                                if (r < 0)
-                                        return bus_log_parse_error(r);
-                                if (r == 0)
-                                        break;
-
-                                r = sd_bus_message_read(m, "i", &family);
-                                if (r < 0)
-                                        return bus_log_parse_error(r);
-
-                                r = sd_bus_message_read_array(m, 'y', &ap, &an);
-                                if (r < 0)
-                                        return bus_log_parse_error(r);
-
-                                r = sd_bus_message_read(m, "u", &prefixlen);
-                                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 (!IN_SET(family, AF_INET, AF_INET6))
-                                        continue;
-
-                                if (an != FAMILY_ADDRESS_SIZE(family))
-                                        continue;
-
-                                if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
-                                        continue;
-
-                                if (in_addr_prefix_to_string(family, (union in_addr_union *) ap, prefixlen, &str) < 0)
-                                        continue;
-
-                                if (!strextend_with_separator(&addresses, " ", str, NULL))
-                                        return log_oom();
-                        }
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (all || !isempty(addresses))
-                                bus_print_property_value(name, expected_value, value, strempty(addresses));
-
-                        return 1;
-
-                } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
-                        _cleanup_free_ char *paths = NULL;
-                        const char *source, *dest;
-                        int ignore_enoent;
-                        uint64_t rbind;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssbt)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(ssbt)", &source, &dest, &ignore_enoent, &rbind)) > 0) {
-                                _cleanup_free_ char *str = NULL;
-
-                                if (isempty(source))
-                                        continue;
-
-                                if (asprintf(&str, "%s%s%s%s%s",
-                                             ignore_enoent ? "-" : "",
-                                             source,
-                                             isempty(dest) ? "" : ":",
-                                             strempty(dest),
-                                             rbind == MS_REC ? ":rbind" : "") < 0)
-                                        return log_oom();
-
-                                if (!strextend_with_separator(&paths, " ", str, NULL))
-                                        return log_oom();
-                        }
-                        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 (all || !isempty(paths))
-                                bus_print_property_value(name, expected_value, value, strempty(paths));
-
-                        return 1;
-
-                } else if (streq(name, "TemporaryFileSystem")) {
-                        _cleanup_free_ char *paths = NULL;
-                        const char *target, *option;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read(m, "(ss)", &target, &option)) > 0) {
-                                _cleanup_free_ char *str = NULL;
-
-                                if (isempty(target))
-                                        continue;
-
-                                if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0)
-                                        return log_oom();
-
-                                if (!strextend_with_separator(&paths, " ", str, NULL))
-                                        return log_oom();
-                        }
-                        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 (all || !isempty(paths))
-                                bus_print_property_value(name, expected_value, value, strempty(paths));
-
-                        return 1;
-
-                } else if (streq(name, "LogExtraFields")) {
-                        _cleanup_free_ char *fields = NULL;
-                        const void *p;
-                        size_t sz;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "ay");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        while ((r = sd_bus_message_read_array(m, 'y', &p, &sz)) > 0) {
-                                _cleanup_free_ char *str = NULL;
-                                const char *eq;
-
-                                if (memchr(p, 0, sz))
-                                        continue;
-
-                                eq = memchr(p, '=', sz);
-                                if (!eq)
-                                        continue;
-
-                                if (!journal_field_valid(p, eq - (const char*) p, false))
-                                        continue;
-
-                                str = malloc(sz + 1);
-                                if (!str)
-                                        return log_oom();
-
-                                memcpy(str, p, sz);
-                                str[sz] = '\0';
-
-                                if (!utf8_is_valid(str))
-                                        continue;
-
-                                if (!strextend_with_separator(&fields, " ", str, NULL))
-                                        return log_oom();
-                        }
-                        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 (all || !isempty(fields))
-                                bus_print_property_value(name, expected_value, value, strempty(fields));
-
-                        return 1;
-                } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes", "EffectiveCPUs", "EffectiveMemoryNodes")) {
-                        _cleanup_free_ char *affinity = NULL;
-                        _cleanup_(cpu_set_reset) CPUSet set = {};
-                        const void *a;
-                        size_t n;
-
-                        r = sd_bus_message_read_array(m, 'y', &a, &n);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        r = cpu_set_from_dbus(a, n, &set);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to deserialize %s: %m", name);
-
-                        affinity = cpu_set_to_range_string(&set);
-                        if (!affinity)
-                                return log_oom();
-
-                        bus_print_property_value(name, expected_value, value, affinity);
-
-                        return 1;
-                } else if (streq(name, "MountImages")) {
-                        _cleanup_free_ char *paths = NULL;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssba(ss))");
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        for (;;) {
-                                _cleanup_free_ char *str = NULL;
-                                const char *source, *destination, *partition, *mount_options;
-                                int ignore_enoent;
-
-                                r = sd_bus_message_enter_container(m, 'r', "ssba(ss)");
-                                if (r < 0)
-                                        return r;
-
-                                r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
-                                if (r <= 0)
-                                        break;
-
-                                str = strjoin(ignore_enoent ? "-" : "",
-                                              source,
-                                              ":",
-                                              destination);
-                                if (!str)
-                                        return log_oom();
-
-                                r = sd_bus_message_enter_container(m, 'a', "(ss)");
-                                if (r < 0)
-                                        return r;
-
-                                while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0) {
-                                        _cleanup_free_ char *previous = NULL;
-
-                                        previous = TAKE_PTR(str);
-                                        str = strjoin(strempty(previous), previous ? ":" : "", partition, ":", mount_options);
-                                        if (!str)
-                                                return log_oom();
-                                }
-                                if (r < 0)
-                                        return r;
-
-                                if (!strextend_with_separator(&paths, " ", str, NULL))
-                                        return log_oom();
-
-                                r = sd_bus_message_exit_container(m);
-                                if (r < 0)
-                                        return r;
-
-                                r = sd_bus_message_exit_container(m);
-                                if (r < 0)
-                                        return r;
-                        }
-                        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 (all || !isempty(paths))
-                                bus_print_property_value(name, expected_value, value, strempty(paths));
-
-                        return 1;
-
-                }
-
-                break;
-        }
-
-        return 0;
-}
-
-typedef enum SystemctlShowMode{
-        SYSTEMCTL_SHOW_PROPERTIES,
-        SYSTEMCTL_SHOW_STATUS,
-        SYSTEMCTL_SHOW_HELP,
-        _SYSTEMCTL_SHOW_MODE_MAX,
-        _SYSTEMCTL_SHOW_MODE_INVALID = -1,
-} SystemctlShowMode;
-
-static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
-        [SYSTEMCTL_SHOW_PROPERTIES] = "show",
-        [SYSTEMCTL_SHOW_STATUS] = "status",
-        [SYSTEMCTL_SHOW_HELP] = "help",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
-
-static int show_one(
-                sd_bus *bus,
-                const char *path,
-                const char *unit,
-                SystemctlShowMode show_mode,
-                bool *new_line,
-                bool *ellipsized) {
-
-        static const struct bus_properties_map property_map[] = {
-                { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
-                { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
-                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
-                { "Documentation",                  "as",              NULL,           offsetof(UnitStatusInfo, documentation)                     },
-                {}
-        }, status_map[] = {
-                { "Id",                             "s",               NULL,           offsetof(UnitStatusInfo, id)                                },
-                { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
-                { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
-                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
-                { "SubState",                       "s",               NULL,           offsetof(UnitStatusInfo, sub_state)                         },
-                { "UnitFileState",                  "s",               NULL,           offsetof(UnitStatusInfo, unit_file_state)                   },
-                { "UnitFilePreset",                 "s",               NULL,           offsetof(UnitStatusInfo, unit_file_preset)                  },
-                { "Description",                    "s",               NULL,           offsetof(UnitStatusInfo, description)                       },
-                { "Following",                      "s",               NULL,           offsetof(UnitStatusInfo, following)                         },
-                { "Documentation",                  "as",              NULL,           offsetof(UnitStatusInfo, documentation)                     },
-                { "FragmentPath",                   "s",               NULL,           offsetof(UnitStatusInfo, fragment_path)                     },
-                { "SourcePath",                     "s",               NULL,           offsetof(UnitStatusInfo, source_path)                       },
-                { "ControlGroup",                   "s",               NULL,           offsetof(UnitStatusInfo, control_group)                     },
-                { "DropInPaths",                    "as",              NULL,           offsetof(UnitStatusInfo, dropin_paths)                      },
-                { "LoadError",                      "(ss)",            map_load_error, offsetof(UnitStatusInfo, load_error)                        },
-                { "Result",                         "s",               NULL,           offsetof(UnitStatusInfo, result)                            },
-                { "TriggeredBy",                    "as",              NULL,           offsetof(UnitStatusInfo, triggered_by)                      },
-                { "Triggers",                       "as",              NULL,           offsetof(UnitStatusInfo, triggers)                          },
-                { "InactiveExitTimestamp",          "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp)           },
-                { "InactiveExitTimestampMonotonic", "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
-                { "ActiveEnterTimestamp",           "t",               NULL,           offsetof(UnitStatusInfo, active_enter_timestamp)            },
-                { "ActiveExitTimestamp",            "t",               NULL,           offsetof(UnitStatusInfo, active_exit_timestamp)             },
-                { "InactiveEnterTimestamp",         "t",               NULL,           offsetof(UnitStatusInfo, inactive_enter_timestamp)          },
-                { "NeedDaemonReload",               "b",               NULL,           offsetof(UnitStatusInfo, need_daemon_reload)                },
-                { "Transient",                      "b",               NULL,           offsetof(UnitStatusInfo, transient)                         },
-                { "ExecMainPID",                    "u",               NULL,           offsetof(UnitStatusInfo, main_pid)                          },
-                { "MainPID",                        "u",               map_main_pid,   0                                                           },
-                { "ControlPID",                     "u",               NULL,           offsetof(UnitStatusInfo, control_pid)                       },
-                { "StatusText",                     "s",               NULL,           offsetof(UnitStatusInfo, status_text)                       },
-                { "PIDFile",                        "s",               NULL,           offsetof(UnitStatusInfo, pid_file)                          },
-                { "StatusErrno",                    "i",               NULL,           offsetof(UnitStatusInfo, status_errno)                      },
-                { "ExecMainStartTimestamp",         "t",               NULL,           offsetof(UnitStatusInfo, start_timestamp)                   },
-                { "ExecMainExitTimestamp",          "t",               NULL,           offsetof(UnitStatusInfo, exit_timestamp)                    },
-                { "ExecMainCode",                   "i",               NULL,           offsetof(UnitStatusInfo, exit_code)                         },
-                { "ExecMainStatus",                 "i",               NULL,           offsetof(UnitStatusInfo, exit_status)                       },
-                { "LogNamespace",                   "s",               NULL,           offsetof(UnitStatusInfo, log_namespace)                     },
-                { "ConditionTimestamp",             "t",               NULL,           offsetof(UnitStatusInfo, condition_timestamp)               },
-                { "ConditionResult",                "b",               NULL,           offsetof(UnitStatusInfo, condition_result)                  },
-                { "Conditions",                     "a(sbbsi)",        map_conditions, 0                                                           },
-                { "AssertTimestamp",                "t",               NULL,           offsetof(UnitStatusInfo, assert_timestamp)                  },
-                { "AssertResult",                   "b",               NULL,           offsetof(UnitStatusInfo, assert_result)                     },
-                { "Asserts",                        "a(sbbsi)",        map_asserts,    0                                                           },
-                { "NextElapseUSecRealtime",         "t",               NULL,           offsetof(UnitStatusInfo, next_elapse_real)                  },
-                { "NextElapseUSecMonotonic",        "t",               NULL,           offsetof(UnitStatusInfo, next_elapse_monotonic)             },
-                { "NAccepted",                      "u",               NULL,           offsetof(UnitStatusInfo, n_accepted)                        },
-                { "NConnections",                   "u",               NULL,           offsetof(UnitStatusInfo, n_connections)                     },
-                { "NRefused",                       "u",               NULL,           offsetof(UnitStatusInfo, n_refused)                         },
-                { "Accept",                         "b",               NULL,           offsetof(UnitStatusInfo, accept)                            },
-                { "Listen",                         "a(ss)",           map_listen,     offsetof(UnitStatusInfo, listen)                            },
-                { "SysFSPath",                      "s",               NULL,           offsetof(UnitStatusInfo, sysfs_path)                        },
-                { "Where",                          "s",               NULL,           offsetof(UnitStatusInfo, where)                             },
-                { "What",                           "s",               NULL,           offsetof(UnitStatusInfo, what)                              },
-                { "MemoryCurrent",                  "t",               NULL,           offsetof(UnitStatusInfo, memory_current)                    },
-                { "DefaultMemoryMin",               "t",               NULL,           offsetof(UnitStatusInfo, default_memory_min)                },
-                { "DefaultMemoryLow",               "t",               NULL,           offsetof(UnitStatusInfo, default_memory_low)                },
-                { "MemoryMin",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_min)                        },
-                { "MemoryLow",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_low)                        },
-                { "MemoryHigh",                     "t",               NULL,           offsetof(UnitStatusInfo, memory_high)                       },
-                { "MemoryMax",                      "t",               NULL,           offsetof(UnitStatusInfo, memory_max)                        },
-                { "MemorySwapMax",                  "t",               NULL,           offsetof(UnitStatusInfo, memory_swap_max)                   },
-                { "MemoryLimit",                    "t",               NULL,           offsetof(UnitStatusInfo, memory_limit)                      },
-                { "CPUUsageNSec",                   "t",               NULL,           offsetof(UnitStatusInfo, cpu_usage_nsec)                    },
-                { "TasksCurrent",                   "t",               NULL,           offsetof(UnitStatusInfo, tasks_current)                     },
-                { "TasksMax",                       "t",               NULL,           offsetof(UnitStatusInfo, tasks_max)                         },
-                { "IPIngressBytes",                 "t",               NULL,           offsetof(UnitStatusInfo, ip_ingress_bytes)                  },
-                { "IPEgressBytes",                  "t",               NULL,           offsetof(UnitStatusInfo, ip_egress_bytes)                   },
-                { "IOReadBytes",                    "t",               NULL,           offsetof(UnitStatusInfo, io_read_bytes)                     },
-                { "IOWriteBytes",                   "t",               NULL,           offsetof(UnitStatusInfo, io_write_bytes)                    },
-                { "ExecCondition",                  "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecConditionEx",                "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecStartPre",                   "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStartPreEx",                 "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecStart",                      "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStartEx",                    "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecStartPost",                  "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStartPostEx",                "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecReload",                     "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecReloadEx",                   "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecStopPre",                    "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStop",                       "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStopEx",                     "a(sasasttttuii)", map_exec,       0                                                           },
-                { "ExecStopPost",                   "a(sasbttttuii)",  map_exec,       0                                                           },
-                { "ExecStopPostEx",                 "a(sasasttttuii)", map_exec,       0                                                           },
-                {}
-        };
-
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_set_free_ Set *found_properties = NULL;
-        _cleanup_(unit_status_info_free) UnitStatusInfo info = {
-                .memory_current = (uint64_t) -1,
-                .memory_high = CGROUP_LIMIT_MAX,
-                .memory_max = CGROUP_LIMIT_MAX,
-                .memory_swap_max = CGROUP_LIMIT_MAX,
-                .memory_limit = (uint64_t) -1,
-                .cpu_usage_nsec = (uint64_t) -1,
-                .tasks_current = (uint64_t) -1,
-                .tasks_max = (uint64_t) -1,
-                .ip_ingress_bytes = (uint64_t) -1,
-                .ip_egress_bytes = (uint64_t) -1,
-                .io_read_bytes = UINT64_MAX,
-                .io_write_bytes = UINT64_MAX,
-        };
-        char **pp;
-        int r;
-
-        assert(path);
-        assert(new_line);
-
-        log_debug("Showing one %s", path);
-
-        r = bus_map_all_properties(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        show_mode == SYSTEMCTL_SHOW_STATUS ? status_map : property_map,
-                        BUS_MAP_BOOLEAN_AS_BOOL,
-                        &error,
-                        &reply,
-                        &info);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
-
-        if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
-                log_full(show_mode == SYSTEMCTL_SHOW_STATUS ? LOG_ERR : LOG_DEBUG,
-                         "Unit %s could not be found.", unit);
-
-                if (show_mode == SYSTEMCTL_SHOW_STATUS)
-                        return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
-                else if (show_mode == SYSTEMCTL_SHOW_HELP)
-                        return -ENOENT;
-        }
-
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
-
-        if (show_mode == SYSTEMCTL_SHOW_STATUS) {
-                print_status_info(bus, &info, ellipsized);
-
-                if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
-                        return EXIT_PROGRAM_NOT_RUNNING;
-
-                return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
-
-        } else if (show_mode == SYSTEMCTL_SHOW_HELP) {
-                show_unit_help(&info);
-                return 0;
-        }
-
-        r = sd_bus_message_rewind(reply, true);
-        if (r < 0)
-                return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
-
-        r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_value, arg_all, &found_properties);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        STRV_FOREACH(pp, arg_properties)
-                if (!set_contains(found_properties, *pp))
-                        log_debug("Property %s does not exist.", *pp);
-
-        return 0;
-}
-
-static int get_unit_dbus_path_by_pid(
-                sd_bus *bus,
-                uint32_t pid,
-                char **unit) {
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        char *u;
-        int r;
-
-        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
-
-        r = sd_bus_message_read(reply, "o", &u);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        u = strdup(u);
-        if (!u)
-                return log_oom();
-
-        *unit = u;
-        return 0;
-}
-
-static int show_all(
-                sd_bus *bus,
-                bool *new_line,
-                bool *ellipsized) {
-
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_free_ UnitInfo *unit_infos = NULL;
-        const UnitInfo *u;
-        unsigned c;
-        int r, ret = 0;
-
-        r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        c = (unsigned) r;
-
-        typesafe_qsort(unit_infos, c, compare_unit_info);
-
-        for (u = unit_infos; u < unit_infos + c; u++) {
-                _cleanup_free_ char *p = NULL;
-
-                p = unit_dbus_path_from_name(u->id);
-                if (!p)
-                        return log_oom();
-
-                r = show_one(bus, p, u->id, SYSTEMCTL_SHOW_STATUS, new_line, ellipsized);
-                if (r < 0)
-                        return r;
-                else if (r > 0 && ret == 0)
-                        ret = r;
-        }
-
-        return ret;
-}
-
-static int show_system_status(sd_bus *bus) {
-        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(machine_info_clear) struct machine_info mi = {};
-        _cleanup_free_ char *hn = NULL;
-        const char *on, *off;
-        int r;
-
-        hn = gethostname_malloc();
-        if (!hn)
-                return log_oom();
-
-        r = bus_map_all_properties(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        machine_info_property_map,
-                        BUS_MAP_STRDUP,
-                        &error,
-                        NULL,
-                        &mi);
-        if (r < 0)
-                return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
-
-        if (streq_ptr(mi.state, "degraded")) {
-                on = ansi_highlight_red();
-                off = ansi_normal();
-        } else if (streq_ptr(mi.state, "running")) {
-                on = ansi_highlight_green();
-                off = ansi_normal();
-        } else {
-                on = ansi_highlight_yellow();
-                off = ansi_normal();
-        }
-
-        printf("%s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
-
-        printf("    State: %s%s%s\n",
-               on, strna(mi.state), off);
-
-        printf("     Jobs: %" PRIu32 " queued\n", mi.n_jobs);
-        printf("   Failed: %" PRIu32 " units\n", mi.n_failed_units);
-
-        printf("    Since: %s; %s\n",
-               format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
-               format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
-
-        printf("   CGroup: %s\n", mi.control_group ?: "/");
-        if (IN_SET(arg_transport,
-                   BUS_TRANSPORT_LOCAL,
-                   BUS_TRANSPORT_MACHINE)) {
-                static const char prefix[] = "           ";
-                unsigned c;
-
-                c = columns();
-                if (c > sizeof(prefix) - 1)
-                        c -= sizeof(prefix) - 1;
-                else
-                        c = 0;
-
-                show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
-        }
-
-        return 0;
-}
-
-static int show(int argc, char *argv[], void *userdata) {
-        bool new_line = false, ellipsized = false;
-        SystemctlShowMode show_mode;
-        int r, ret = 0;
-        sd_bus *bus;
-
-        assert(argv);
-
-        show_mode = systemctl_show_mode_from_string(argv[0]);
-        if (show_mode < 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Invalid argument.");
-
-        if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "'help' command expects one or more unit names.\n"
-                                       "(Alternatively, help for systemctl itself may be shown with --help)");
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        /* If no argument is specified inspect the manager itself */
-        if (show_mode == SYSTEMCTL_SHOW_PROPERTIES && argc <= 1)
-                return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
-
-        if (show_mode == SYSTEMCTL_SHOW_STATUS && argc <= 1) {
-
-                show_system_status(bus);
-                new_line = true;
-
-                if (arg_all)
-                        ret = show_all(bus, &new_line, &ellipsized);
-        } else {
-                _cleanup_free_ char **patterns = NULL;
-                char **name;
-
-                STRV_FOREACH(name, strv_skip(argv, 1)) {
-                        _cleanup_free_ char *path = NULL, *unit = NULL;
-                        uint32_t id;
-
-                        if (safe_atou32(*name, &id) < 0) {
-                                if (strv_push(&patterns, *name) < 0)
-                                        return log_oom();
-
-                                continue;
-                        } else if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) {
-                                /* Interpret as job id */
-                                if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
-                                        return log_oom();
-
-                        } else {
-                                /* Interpret as PID */
-                                r = get_unit_dbus_path_by_pid(bus, id, &path);
-                                if (r < 0) {
-                                        ret = r;
-                                        continue;
-                                }
-
-                                r = unit_name_from_dbus_path(path, &unit);
-                                if (r < 0)
-                                        return log_oom();
-                        }
-
-                        r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
-                        if (r < 0)
-                                return r;
-                        else if (r > 0 && ret == 0)
-                                ret = r;
-                }
-
-                if (!strv_isempty(patterns)) {
-                        _cleanup_strv_free_ char **names = NULL;
-
-                        r = expand_names(bus, patterns, NULL, &names, NULL);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to expand names: %m");
-
-                        r = maybe_extend_with_unit_dependencies(bus, &names);
-                        if (r < 0)
-                                return r;
-
-                        STRV_FOREACH(name, names) {
-                                _cleanup_free_ char *path;
-
-                                path = unit_dbus_path_from_name(*name);
-                                if (!path)
-                                        return log_oom();
-
-                                r = show_one(bus, path, *name, show_mode, &new_line, &ellipsized);
-                                if (r < 0)
-                                        return r;
-                                if (r > 0 && ret == 0)
-                                        ret = r;
-                        }
-                }
-        }
-
-        if (ellipsized && !arg_quiet)
-                printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
-
-        return ret;
-}
-
-static int cat(int argc, char *argv[], void *userdata) {
-        _cleanup_(lookup_paths_free) LookupPaths lp = {};
-        _cleanup_strv_free_ char **names = NULL;
-        char **name;
-        sd_bus *bus;
-        bool first = true;
-        int r, rc = 0;
-
-        /* Include all units by default — i.e. continue as if the --all
-         * option was used */
-        if (strv_isempty(arg_states))
-                arg_all = true;
-
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
-
-        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine unit paths: %m");
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        r = maybe_extend_with_unit_dependencies(bus, &names);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        STRV_FOREACH(name, names) {
-                _cleanup_free_ char *fragment_path = NULL;
-                _cleanup_strv_free_ char **dropin_paths = NULL;
-
-                r = unit_find_paths(bus, *name, &lp, false, &fragment_path, &dropin_paths);
-                if (r == -ERFKILL) {
-                        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());
-                        continue;
-                }
-                if (r < 0)
-                        return r;
-                if (r == 0) {
-                        /* Skip units which have no on-disk counterpart, but
-                         * propagate the error to the user */
-                        rc = -ENOENT;
-                        continue;
-                }
-
-                if (first)
-                        first = false;
-                else
-                        puts("");
-
-                if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
-                        fprintf(stderr,
-                                "%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
-                                "%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
-                                "%s# If fragments or drop-ins were added or removed, they are not properly reflected in this output.\n"
-                                "%s# Run 'systemctl%s daemon-reload' to reload units.%s\n",
-                                ansi_highlight_red(),
-                                *name,
-                                ansi_highlight_red(),
-                                ansi_highlight_red(),
-                                ansi_highlight_red(),
-                                arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
-                                ansi_normal());
-
-                r = cat_files(fragment_path, dropin_paths, 0);
-                if (r < 0)
-                        return r;
-        }
-
-        return rc;
-}
-
-static int set_property(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *n = NULL;
-        UnitType t;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetUnitProperties");
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n);
-        if (r < 0)
-                return log_error_errno(r, "Failed to mangle unit name: %m");
-
-        t = unit_name_to_type(n);
-        if (t < 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit type: %s", n);
-
-        r = sd_bus_message_append(m, "sb", n, arg_runtime);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_call(bus, m, 0, &error, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
-
-        return 0;
-}
-
-static int daemon_reload(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        const char *method;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        switch (arg_action) {
-
-        case ACTION_RELOAD:
-                method = "Reload";
-                break;
-
-        case ACTION_REEXEC:
-                method = "Reexecute";
-                break;
-
-        case ACTION_SYSTEMCTL:
-                method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
-                                     /* "daemon-reload" */ "Reload";
-                break;
-
-        default:
-                assert_not_reached("Unexpected action");
-        }
-
-        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
-         * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
-         * their timeout, and for everything else there's the same time budget in place. */
-
-        r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
-
-        /* On reexecution, we expect a disconnect, not a reply */
-        if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
-                r = 0;
-
-        if (r < 0 && arg_action == ACTION_SYSTEMCTL)
-                return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
-
-        /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
-         * old ways of doing things, hence don't log any error in that case here. */
-
-        return r < 0 ? r : 0;
-}
-
-static int trivial_method(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *method;
-        sd_bus *bus;
-        int r;
-
-        if (arg_dry_run)
-                return 0;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        method =
-                streq(argv[0], "clear-jobs")    ||
-                streq(argv[0], "cancel")        ? "ClearJobs" :
-                streq(argv[0], "reset-failed")  ? "ResetFailed" :
-                streq(argv[0], "halt")          ? "Halt" :
-                streq(argv[0], "reboot")        ? "Reboot" :
-                streq(argv[0], "kexec")         ? "KExec" :
-                streq(argv[0], "exit")          ? "Exit" :
-                             /* poweroff */       "PowerOff";
-
-        r = bus_call_method(bus, bus_systemd_mgr, method, &error, NULL, NULL);
-        if (r < 0 && arg_action == ACTION_SYSTEMCTL)
-                return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
-
-        /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
-         * old ways of doing things, hence don't log any error in that case here. */
-
-        return r < 0 ? r : 0;
-}
-
-static int reset_failed(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        sd_bus *bus;
-        char **name;
-        int r, q;
-
-        if (argc <= 1)
-                return trivial_method(argc, argv, userdata);
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        STRV_FOREACH(name, names) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
-                q = bus_call_method(bus, bus_systemd_mgr, "ResetFailedUnit", &error, NULL, "s", *name);
-                if (q < 0) {
-                        log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
-                        if (r == 0)
-                                r = q;
-                }
-        }
-
-        return r;
-}
-
-static int print_variable(const char *s) {
-        const char *sep;
-        _cleanup_free_ char *esc = NULL;
-
-        sep = strchr(s, '=');
-        if (!sep)
-                return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
-                                       "Invalid environment block");
-
-        esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
-        if (!esc)
-                return log_oom();
-
-        printf("%.*s=%s\n", (int)(sep-s), s, esc);
-        return 0;
-}
-
-static int show_environment(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *text;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        (void) pager_open(arg_pager_flags);
-
-        r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
-        if (r < 0)
-                return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
-
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
-                r = print_variable(text);
-                if (r < 0)
-                        return r;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return 0;
-}
-
-static int switch_root(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *cmdline_init = NULL;
-        const char *root, *init;
-        sd_bus *bus;
-        int r;
-
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch root remotely.");
-
-        if (argc < 2 || argc > 3)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments.");
-
-        root = argv[1];
-
-        if (argc >= 3)
-                init = argv[2];
-        else {
-                r = proc_cmdline_get_key("init", 0, &cmdline_init);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
-
-                init = cmdline_init;
-        }
-
-        init = empty_to_null(init);
-        if (init) {
-                const char *root_systemd_path = NULL, *root_init_path = NULL;
-
-                root_systemd_path = prefix_roota(root, "/" SYSTEMD_BINARY_PATH);
-                root_init_path = prefix_roota(root, init);
-
-                /* If the passed init is actually the same as the
-                 * systemd binary, then let's suppress it. */
-                if (files_same(root_init_path, root_systemd_path, 0) > 0)
-                        init = NULL;
-        }
-
-        /* Instruct PID1 to exclude us from its killing spree applied during the transition. Otherwise we
-         * would exit with a failure status even though the switch to the new root has succeed. */
-        assert(saved_argv);
-        assert(saved_argv[0]);
-        saved_argv[0][0] = '@';
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        /* If we are slow to exit after the root switch, the new systemd instance
-         * will send us a signal to terminate. Just ignore it and exit normally.
-         * This way the unit does not end up as failed.
-         */
-        r = ignore_signals(SIGTERM, -1);
-        if (r < 0)
-                log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
-
-        log_debug("Switching root - root: %s; init: %s", root, strna(init));
-
-        r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
-        if (r < 0) {
-                (void) default_signals(SIGTERM, -1);
-
-                return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
-        }
-
-        return 0;
-}
-
-static void give_log_control1_hint(const char *name) {
-        _cleanup_free_ char *link = NULL;
-
-        if (arg_quiet)
-                return;
-
-        (void) terminal_urlify_man("org.freedesktop.LogControl1", "5", &link);
-
-        log_notice("Hint: the service must declare BusName= and implement the appropriate D-Bus interface.\n"
-                   "      See the %s for details.", link ?: "org.freedesktop.LogControl1(5) man page");
-}
-
-static int log_setting_internal(sd_bus *bus, const BusLocator* bloc, const char *verb, const char *value) {
-        assert(bus);
-        assert(STR_IN_SET(verb, "log-level", "log-target", "service-log-level", "service-log-target"));
-
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        bool level = endswith(verb, "log-level");
-        int r;
-
-        if (value) {
-                if (level) {
-                        if (log_level_from_string(value) < 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "\"%s\" is not a valid log level.", value);
-                }
-
-                r = bus_set_property(bus, bloc,
-                                     level ? "LogLevel" : "LogTarget",
-                                     &error, "s", value);
-                if (r >= 0)
-                        return 0;
-
-                log_error_errno(r, "Failed to set log %s of %s to %s: %s",
-                                level ? "level" : "target",
-                                bloc->destination, value, bus_error_message(&error, r));
-        } else {
-                _cleanup_free_ char *t = NULL;
-
-                r = bus_get_property_string(bus, bloc,
-                                            level ? "LogLevel" : "LogTarget",
-                                            &error, &t);
-                if (r >= 0) {
-                        puts(t);
-                        return 0;
-                }
-
-                log_error_errno(r, "Failed to get log %s of %s: %s",
-                                level ? "level" : "target",
-                                bloc->destination, bus_error_message(&error, r));
-        }
-
-        if (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
-                                           SD_BUS_ERROR_UNKNOWN_OBJECT,
-                                           SD_BUS_ERROR_UNKNOWN_INTERFACE,
-                                           SD_BUS_ERROR_UNKNOWN_PROPERTY))
-                give_log_control1_hint(bloc->destination);
-        return r;
-}
-
-static int log_setting(int argc, char *argv[], void *userdata) {
-        sd_bus *bus;
-        int r;
-
-        assert(argc >= 1 && argc <= 2);
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        return log_setting_internal(bus, bus_systemd_mgr, argv[0], argv[1]);
-}
-
-static int service_name_to_dbus(sd_bus *bus, const char *name, char **ret_dbus_name) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *bus_name = NULL;
-        int r;
-
-        /* First, look for the BusName= property */
-        _cleanup_free_ char *dbus_path = unit_dbus_path_from_name(name);
-        if (!dbus_path)
-                return log_oom();
-
-        r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                dbus_path,
-                                "org.freedesktop.systemd1.Service",
-                                "BusName",
-                                &error,
-                                &bus_name);
-        if (r < 0)
-                return log_error_errno(r, "Failed to obtain BusName= property of %s: %s",
-                                       name, bus_error_message(&error, r));
-
-        if (isempty(bus_name)) {
-                log_error("Unit %s doesn't declare BusName=.", name);
-                give_log_control1_hint(name);
-                return -ENOLINK;
-        }
-
-        *ret_dbus_name = TAKE_PTR(bus_name);
-        return 0;
-}
-
-static int service_log_setting(int argc, char *argv[], void *userdata) {
-        sd_bus *bus;
-        _cleanup_free_ char *unit = NULL, *dbus_name = NULL;
-        int r;
-
-        assert(argc >= 2 && argc <= 3);
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = unit_name_mangle_with_suffix(argv[1], argv[0],
-                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
-                                         ".service", &unit);
-        if (r < 0)
-                return log_error_errno(r, "Failed to mangle unit name: %m");
-
-        r = service_name_to_dbus(bus, unit, &dbus_name);
-        if (r < 0)
-                return r;
-
-        const BusLocator bloc = {
-                .destination = dbus_name,
-                .path = "/org/freedesktop/LogControl1",
-                .interface = "org.freedesktop.LogControl1",
-        };
-
-        return log_setting_internal(bus, &bloc, argv[0], argv[2]);
-}
-
-static int service_watchdogs(int argc, char *argv[], void *userdata) {
-        sd_bus *bus;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        int b, r;
-
-        assert(argv);
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        if (argc == 1) {
-                /* get ServiceWatchdogs */
-                r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
-
-                printf("%s\n", yes_no(!!b));
-
-        } else {
-                /* set ServiceWatchdogs */
-                assert(argc == 2);
-
-                b = parse_boolean(argv[1]);
-                if (b < 0)
-                        return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
-
-                r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
-        }
-
-        return 0;
-}
-
-static int set_environment(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        const char *method;
-        sd_bus *bus;
-        int r;
-
-        assert(argc > 1);
-        assert(argv);
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        method = streq(argv[0], "set-environment")
-                ? "SetEnvironment"
-                : "UnsetEnvironment";
-
-        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_call(bus, m, 0, &error, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
-
-        return 0;
-}
-
-static int import_environment(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        polkit_agent_open_maybe();
-
-        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        if (argc < 2)
-                r = sd_bus_message_append_strv(m, environ);
-        else {
-                char **a, **b;
-
-                r = sd_bus_message_open_container(m, 'a', "s");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                STRV_FOREACH(a, strv_skip(argv, 1)) {
-
-                        if (!env_name_is_valid(*a))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid environment variable name: %s", *a);
-
-                        STRV_FOREACH(b, environ) {
-                                const char *eq;
-
-                                eq = startswith(*b, *a);
-                                if (eq && *eq == '=') {
-
-                                        r = sd_bus_message_append(m, "s", *b);
-                                        if (r < 0)
-                                                return bus_log_create_error(r);
-
-                                        break;
-                                }
-                        }
-                }
-
-                r = sd_bus_message_close_container(m);
-        }
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_call(bus, m, 0, &error, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
-
-        return 0;
-}
-
-static int enable_sysv_units(const char *verb, char **args) {
-        int r = 0;
-
-#if HAVE_SYSV_COMPAT
-        _cleanup_(lookup_paths_free) LookupPaths paths = {};
-        unsigned f = 0;
-
-        /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
-
-        if (arg_scope != UNIT_FILE_SYSTEM)
-                return 0;
-
-        if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
-                return 0;
-
-        if (!STR_IN_SET(verb,
-                        "enable",
-                        "disable",
-                        "is-enabled"))
-                return 0;
-
-        r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
-        if (r < 0)
-                return r;
-
-        r = 0;
-        while (args[f]) {
-
-                const char *argv[] = {
-                        ROOTLIBEXECDIR "/systemd-sysv-install",
-                        NULL, /* --root= */
-                        NULL, /* verb */
-                        NULL, /* service */
-                        NULL,
-                };
-
-                _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL, *v = NULL;
-                bool found_native = false, found_sysv;
-                const char *name;
-                unsigned c = 1;
-                pid_t pid;
-                int j;
-
-                name = args[f++];
-
-                if (!endswith(name, ".service"))
-                        continue;
-
-                if (path_is_absolute(name))
-                        continue;
-
-                j = unit_file_exists(arg_scope, &paths, name);
-                if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
-                        return log_error_errno(j, "Failed to look up unit file state: %m");
-                found_native = j != 0;
-
-                /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
-                 * prefer the native unit */
-                if (found_native && streq(verb, "is-enabled"))
-                        continue;
-
-                p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
-                if (!p)
-                        return log_oom();
-
-                p[strlen(p) - STRLEN(".service")] = 0;
-                found_sysv = access(p, F_OK) >= 0;
-                if (!found_sysv)
-                        continue;
-
-                if (!arg_quiet) {
-                        if (found_native)
-                                log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
-                        else
-                                log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
-                }
-
-                if (!isempty(arg_root)) {
-                        q = strjoin("--root=", arg_root);
-                        if (!q)
-                                return log_oom();
-
-                        argv[c++] = q;
-                }
-
-                /* Let's copy the verb, since it's still pointing directly into the original argv[] array we
-                 * got passed, but safe_fork() is likely going to rewrite that for the new child */
-                v = strdup(verb);
-                if (!v)
-                        return log_oom();
-
-                argv[c++] = v;
-                argv[c++] = basename(p);
-                argv[c] = NULL;
-
-                l = strv_join((char**)argv, " ");
-                if (!l)
-                        return log_oom();
-
-                if (!arg_quiet)
-                        log_info("Executing: %s", l);
-
-                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) {
-                        /* Child */
-                        execv(argv[0], (char**) argv);
-                        log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
-                        _exit(EXIT_FAILURE);
-                }
-
-                j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
-                if (j < 0)
-                        return j;
-                if (streq(verb, "is-enabled")) {
-                        if (j == EXIT_SUCCESS) {
-                                if (!arg_quiet)
-                                        puts("enabled");
-                                r = 1;
-                        } else {
-                                if (!arg_quiet)
-                                        puts("disabled");
-                        }
-
-                } else if (j != EXIT_SUCCESS)
-                        return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
-
-                if (found_native)
-                        continue;
-
-                /* Remove this entry, so that we don't try enabling it as native unit */
-                assert(f > 0);
-                f--;
-                assert(args[f] == name);
-                strv_remove(args + f, name);
-        }
-
-#endif
-        return r;
-}
-
-static int mangle_names(const char *operation, char **original_names, char ***mangled_names) {
-        char **i, **l, **name;
-        int r;
-
-        l = i = new(char*, strv_length(original_names) + 1);
-        if (!l)
-                return log_oom();
-
-        STRV_FOREACH(name, original_names) {
-
-                /* When enabling units qualified path names are OK,
-                 * too, hence allow them explicitly. */
-
-                if (is_path(*name)) {
-                        *i = strdup(*name);
-                        if (!*i) {
-                                strv_free(l);
-                                return log_oom();
-                        }
-                } else {
-                        r = unit_name_mangle_with_suffix(*name, operation,
-                                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
-                                                         ".service", i);
-                        if (r < 0) {
-                                *i = NULL;
-                                strv_free(l);
-                                return log_error_errno(r, "Failed to mangle unit name: %m");
-                        }
-                }
-
-                i++;
-        }
-
-        *i = NULL;
-        *mangled_names = l;
-
-        return 0;
-}
-
-static int normalize_filenames(char **names) {
-        char **u;
-        int r;
-
-        STRV_FOREACH(u, names)
-                if (!path_is_absolute(*u)) {
-                        char* normalized_path;
-
-                        if (!isempty(arg_root))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Non-absolute paths are not allowed when --root is used: %s",
-                                                       *u);
-
-                        if (!strchr(*u,'/'))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Link argument does contain at least one directory separator: %s",
-                                                       *u);
-
-                        r = path_make_absolute_cwd(*u, &normalized_path);
-                        if (r < 0)
-                                return r;
-
-                        free_and_replace(*u, normalized_path);
-                }
-
-        return 0;
-}
-
-static int normalize_names(char **names, bool warn_if_path) {
-        char **u;
-        bool was_path = false;
-
-        STRV_FOREACH(u, names) {
-                int r;
-
-                if (!is_path(*u))
-                        continue;
-
-                r = free_and_strdup(u, basename(*u));
-                if (r < 0)
-                        return log_error_errno(r, "Failed to normalize unit file path: %m");
-
-                was_path = true;
-        }
-
-        if (warn_if_path && was_path)
-                log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
-
-        return 0;
-}
-
-static int unit_exists(LookupPaths *lp, const char *unit) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_free_ char *path = NULL;
-        static const struct bus_properties_map property_map[] = {
-                { "LoadState",   "s", NULL, offsetof(UnitStatusInfo, load_state)  },
-                { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state)},
-                {},
-        };
-        UnitStatusInfo info = {};
-        sd_bus *bus;
-        int r;
-
-        if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
-                return unit_find_template_path(unit, lp, NULL, NULL);
-
-        path = unit_dbus_path_from_name(unit);
-        if (!path)
-                return log_oom();
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, 0, &error, &m, &info);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
-
-        return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
-}
-
-static int enable_unit(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        const char *verb = argv[0];
-        UnitFileChange *changes = NULL;
-        size_t n_changes = 0;
-        int carries_install_info = -1;
-        bool ignore_carries_install_info = arg_quiet;
-        int r;
-
-        if (!argv[1])
-                return 0;
-
-        r = mangle_names("to enable", strv_skip(argv, 1), &names);
-        if (r < 0)
-                return r;
-
-        r = enable_sysv_units(verb, names);
-        if (r < 0)
-                return r;
-
-        /* If the operation was fully executed by the SysV compat, let's finish early */
-        if (strv_isempty(names)) {
-                if (arg_no_reload || install_client_side())
-                        return 0;
-                return daemon_reload(argc, argv, userdata);
-        }
-
-        if (streq(verb, "disable")) {
-                r = normalize_names(names, true);
-                if (r < 0)
-                        return r;
-        }
-
-        if (streq(verb, "link")) {
-                r = normalize_filenames(names);
-                if (r < 0)
-                        return r;
-        }
-
-        if (install_client_side()) {
-                UnitFileFlags flags;
-
-                flags = args_to_flags();
-                if (streq(verb, "enable")) {
-                        r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(verb, "disable"))
-                        r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                else if (streq(verb, "reenable")) {
-                        r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(verb, "link"))
-                        r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                else if (streq(verb, "preset")) {
-                        r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
-                } else if (streq(verb, "mask"))
-                        r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                else if (streq(verb, "unmask"))
-                        r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                else if (streq(verb, "revert"))
-                        r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
-                else
-                        assert_not_reached("Unknown verb");
-
-                unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
-                if (r < 0)
-                        goto finish;
-                r = 0;
-        } else {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                bool expect_carries_install_info = false;
-                bool send_runtime = true, send_force = true, send_preset_mode = false;
-                const char *method;
-                sd_bus *bus;
-
-                if (STR_IN_SET(verb, "mask", "unmask")) {
-                        char **name;
-                        _cleanup_(lookup_paths_free) LookupPaths lp = {};
-
-                        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
-                        if (r < 0)
-                                return r;
-
-                        STRV_FOREACH(name, names) {
-                                r = unit_exists(&lp, *name);
-                                if (r < 0)
-                                        return r;
-                                if (r == 0)
-                                        log_notice("Unit %s does not exist, proceeding anyway.", *name);
-                        }
-                }
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                polkit_agent_open_maybe();
-
-                if (streq(verb, "enable")) {
-                        method = "EnableUnitFiles";
-                        expect_carries_install_info = true;
-                } else if (streq(verb, "disable")) {
-                        method = "DisableUnitFiles";
-                        send_force = false;
-                } else if (streq(verb, "reenable")) {
-                        method = "ReenableUnitFiles";
-                        expect_carries_install_info = true;
-                } else if (streq(verb, "link"))
-                        method = "LinkUnitFiles";
-                else if (streq(verb, "preset")) {
-
-                        if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
-                                method = "PresetUnitFilesWithMode";
-                                send_preset_mode = true;
-                        } else
-                                method = "PresetUnitFiles";
-
-                        expect_carries_install_info = true;
-                        ignore_carries_install_info = true;
-                } else if (streq(verb, "mask"))
-                        method = "MaskUnitFiles";
-                else if (streq(verb, "unmask")) {
-                        method = "UnmaskUnitFiles";
-                        send_force = false;
-                } else if (streq(verb, "revert")) {
-                        method = "RevertUnitFiles";
-                        send_runtime = send_force = false;
-                } else
-                        assert_not_reached("Unknown verb");
-
-                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append_strv(m, names);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                if (send_preset_mode) {
-                        r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                if (send_runtime) {
-                        r = sd_bus_message_append(m, "b", arg_runtime);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                if (send_force) {
-                        r = sd_bus_message_append(m, "b", arg_force);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_call(bus, m, 0, &error, &reply);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
-
-                if (expect_carries_install_info) {
-                        r = sd_bus_message_read(reply, "b", &carries_install_info);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-                }
-
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
-                if (r < 0)
-                        goto finish;
-
-                /* Try to reload if enabled */
-                if (!arg_no_reload)
-                        r = daemon_reload(argc, argv, userdata);
-                else
-                        r = 0;
-        }
-
-        if (carries_install_info == 0 && !ignore_carries_install_info)
-                log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
-                           "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
-                           "units). This means they are not meant to be enabled using systemctl.\n"
-                           " \n" /* trick: the space is needed so that the line does not get stripped from output */
-                           "Possible reasons for having this kind of units are:\n"
-                           "%1$s A unit may be statically enabled by being symlinked from another unit's\n"
-                           "  .wants/ or .requires/ directory.\n"
-                           "%1$s A unit's purpose may be to act as a helper for some other unit which has\n"
-                           "  a requirement dependency on it.\n"
-                           "%1$s A unit may be started when needed via activation (socket, path, timer,\n"
-                           "  D-Bus, udev, scripted systemctl call, ...).\n"
-                           "%1$s In case of template units, the unit is meant to be enabled with some\n"
-                           "  instance name specified.",
-                           special_glyph(SPECIAL_GLYPH_BULLET));
-
-        if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
-                sd_bus *bus;
-                size_t len, i;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        goto finish;
-
-                len = strv_length(names);
-                {
-                        char *new_args[len + 2];
-
-                        new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
-                        for (i = 0; i < len; i++)
-                                new_args[i + 1] = basename(names[i]);
-                        new_args[i + 1] = NULL;
-
-                        r = start_unit(len + 1, new_args, userdata);
-                }
-        }
-
-finish:
-        unit_file_changes_free(changes, n_changes);
-
-        return r;
-}
-
-static int add_dependency(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        _cleanup_free_ char *target = NULL;
-        const char *verb = argv[0];
-        UnitFileChange *changes = NULL;
-        size_t n_changes = 0;
-        UnitDependency dep;
-        int r;
-
-        if (!argv[1])
-                return 0;
-
-        r = unit_name_mangle_with_suffix(argv[1], "as target",
-                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
-                                         ".target", &target);
-        if (r < 0)
-                return log_error_errno(r, "Failed to mangle unit name: %m");
-
-        r = mangle_names("as dependency", strv_skip(argv, 2), &names);
-        if (r < 0)
-                return r;
-
-        if (streq(verb, "add-wants"))
-                dep = UNIT_WANTS;
-        else if (streq(verb, "add-requires"))
-                dep = UNIT_REQUIRES;
-        else
-                assert_not_reached("Unknown verb");
-
-        if (install_client_side()) {
-                r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes);
-                unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
-
-                if (r > 0)
-                        r = 0;
-        } else {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                sd_bus *bus;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                polkit_agent_open_maybe();
-
-                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "AddDependencyUnitFiles");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append_strv(m, names);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_call(bus, m, 0, &error, &reply);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
-
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
-                if (r < 0)
-                        goto finish;
-
-                if (arg_no_reload) {
-                        r = 0;
-                        goto finish;
-                }
-
-                r = daemon_reload(argc, argv, userdata);
-        }
-
-finish:
-        unit_file_changes_free(changes, n_changes);
-
-        return r;
-}
-
-static int preset_all(int argc, char *argv[], void *userdata) {
-        UnitFileChange *changes = NULL;
-        size_t n_changes = 0;
-        int r;
-
-        if (install_client_side()) {
-                r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes);
-                unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
-
-                if (r > 0)
-                        r = 0;
-        } else {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                sd_bus *bus;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                polkit_agent_open_maybe();
-
-                r = bus_call_method(
-                                bus,
-                                bus_systemd_mgr,
-                                "PresetAllUnitFiles",
-                                &error,
-                                &reply,
-                                "sbb",
-                                unit_file_preset_mode_to_string(arg_preset_mode),
-                                arg_runtime,
-                                arg_force);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
-
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
-                if (r < 0)
-                        goto finish;
-
-                if (arg_no_reload) {
-                        r = 0;
-                        goto finish;
-                }
-
-                r = daemon_reload(argc, argv, userdata);
-        }
-
-finish:
-        unit_file_changes_free(changes, n_changes);
-
-        return r;
-}
-
-static int show_installation_targets_client_side(const char *name) {
-        UnitFileChange *changes = NULL;
-        size_t n_changes = 0, i;
-        UnitFileFlags flags;
-        char **p;
-        int r;
-
-        p = STRV_MAKE(name);
-        flags = UNIT_FILE_DRY_RUN |
-                (arg_runtime ? UNIT_FILE_RUNTIME : 0);
-
-        r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get file links for %s: %m", name);
-
-        for (i = 0; i < n_changes; i++)
-                if (changes[i].type == UNIT_FILE_UNLINK)
-                        printf("  %s\n", changes[i].path);
-
-        return 0;
-}
-
-static int show_installation_targets(sd_bus *bus, const char *name) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *link;
-        int r;
-
-        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileLinks", &error, &reply, "sb", name, arg_runtime);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
-
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
-                printf("  %s\n", link);
-
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return 0;
-}
-
-static int unit_is_enabled(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        bool enabled;
-        char **name;
-        int r;
-
-        r = mangle_names("to check", strv_skip(argv, 1), &names);
-        if (r < 0)
-                return r;
-
-        r = enable_sysv_units(argv[0], names);
-        if (r < 0)
-                return r;
-
-        enabled = r > 0;
-
-        if (install_client_side()) {
-                STRV_FOREACH(name, names) {
-                        UnitFileState state;
-
-                        r = unit_file_get_state(arg_scope, arg_root, *name, &state);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to get unit file state for %s: %m", *name);
-
-                        if (IN_SET(state,
-                                   UNIT_FILE_ENABLED,
-                                   UNIT_FILE_ENABLED_RUNTIME,
-                                   UNIT_FILE_STATIC,
-                                   UNIT_FILE_ALIAS,
-                                   UNIT_FILE_INDIRECT,
-                                   UNIT_FILE_GENERATED))
-                                enabled = true;
-
-                        if (!arg_quiet) {
-                                puts(unit_file_state_to_string(state));
-                                if (arg_full) {
-                                        r = show_installation_targets_client_side(*name);
-                                        if (r < 0)
-                                                return r;
-                                }
-                        }
-                }
-
-                r = 0;
-        } else {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                sd_bus *bus;
-
-                r = acquire_bus(BUS_MANAGER, &bus);
-                if (r < 0)
-                        return r;
-
-                STRV_FOREACH(name, names) {
-                        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                        const char *s;
-
-                        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", *name);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
-
-                        r = sd_bus_message_read(reply, "s", &s);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
-
-                        if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
-                                enabled = true;
 
-                        if (!arg_quiet) {
-                                puts(s);
-                                if (arg_full) {
-                                        r = show_installation_targets(bus, *name);
-                                        if (r < 0)
-                                                return r;
-                                }
-                        }
-                }
-        }
-
-        return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static int match_startup_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        char **state = userdata;
-        int r;
-
-        assert(state);
-
-        r = bus_get_property_string(sd_bus_message_get_bus(m), bus_systemd_mgr, "SystemState", NULL, state);
-
-        sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r);
-        return 0;
-}
-
-static int is_system_running(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_startup_finished = NULL;
-        _cleanup_(sd_event_unrefp) sd_event* event = NULL;
-        _cleanup_free_ char *state = NULL;
-        sd_bus *bus;
-        int r;
-
-        if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
-                if (!arg_quiet)
-                        puts("offline");
-                return EXIT_FAILURE;
-        }
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        if (arg_wait) {
-                r = sd_event_default(&event);
-                if (r >= 0)
-                        r = sd_bus_attach_event(bus, event, 0);
-                if (r >= 0)
-                        r = bus_match_signal_async(
-                                        bus,
-                                        &slot_startup_finished,
-                                        bus_systemd_mgr,
-                                        "StartupFinished",
-                                        match_startup_finished, NULL, &state);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to request match for StartupFinished: %m");
-                        arg_wait = false;
-                }
-        }
-
-        r = bus_get_property_string(bus, bus_systemd_mgr, "SystemState", &error, &state);
-        if (r < 0) {
-                log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r));
-
-                if (!arg_quiet)
-                        puts("unknown");
-                return EXIT_FAILURE;
-        }
-
-        if (arg_wait && STR_IN_SET(state, "initializing", "starting")) {
-                r = sd_event_loop(event);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to get property from event loop: %m");
-                        if (!arg_quiet)
-                                puts("unknown");
-                        return EXIT_FAILURE;
-                }
-        }
-
-        if (!arg_quiet)
-                puts(state);
-
-        return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(new_path);
-        assert(original_path);
-        assert(ret_tmp_fn);
-
-        r = tempfn_random(new_path, NULL, &t);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
-
-        r = mkdir_parents_label(new_path, 0755);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
-
-        r = mac_selinux_create_file_prepare(original_path, S_IFREG);
-        if (r < 0)
-                return r;
-
-        r = copy_file(original_path, t, 0, 0644, 0, 0, COPY_REFLINK);
-        if (r == -ENOENT) {
-
-                r = touch(t);
-
-                mac_selinux_create_file_clear();
-
-                if (r < 0)
-                        return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
-
-        } else {
-                mac_selinux_create_file_clear();
-
-                if (r < 0)
-                         return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
-        }
-
-        *ret_tmp_fn = TAKE_PTR(t);
-
-        return 0;
-}
-
-static int get_file_to_edit(
-                const LookupPaths *paths,
-                const char *name,
-                char **ret_path) {
-
-        _cleanup_free_ char *path = NULL, *run = NULL;
-
-        assert(name);
-        assert(ret_path);
-
-        path = path_join(paths->persistent_config, name);
-        if (!path)
-                return log_oom();
-
-        if (arg_runtime) {
-                run = path_join(paths->runtime_config, name);
-                if (!run)
-                        return log_oom();
-        }
-
-        if (arg_runtime) {
-                if (access(path, F_OK) >= 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
-                                               "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
-                                               run, path);
-
-                *ret_path = TAKE_PTR(run);
-        } else
-                *ret_path = TAKE_PTR(path);
-
-        return 0;
-}
-
-static int unit_file_create_new(
-                const LookupPaths *paths,
-                const char *unit_name,
-                const char *suffix,
-                char **ret_new_path,
-                char **ret_tmp_path) {
-
-        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
-        const char *ending;
-        int r;
-
-        assert(unit_name);
-        assert(ret_new_path);
-        assert(ret_tmp_path);
-
-        ending = strjoina(unit_name, suffix);
-        r = get_file_to_edit(paths, ending, &new_path);
-        if (r < 0)
-                return r;
-
-        r = create_edit_temp_file(new_path, new_path, &tmp_path);
-        if (r < 0)
-                return r;
-
-        *ret_new_path = TAKE_PTR(new_path);
-        *ret_tmp_path = TAKE_PTR(tmp_path);
-
-        return 0;
-}
-
-static int unit_file_create_copy(
-                const LookupPaths *paths,
-                const char *unit_name,
-                const char *fragment_path,
-                char **ret_new_path,
-                char **ret_tmp_path) {
-
-        _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
-        int r;
-
-        assert(fragment_path);
-        assert(unit_name);
-        assert(ret_new_path);
-        assert(ret_tmp_path);
-
-        r = get_file_to_edit(paths, unit_name, &new_path);
-        if (r < 0)
-                return r;
-
-        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] ", new_path, fragment_path);
-                if (r < 0)
-                        return r;
-                if (response != 'y')
-                        return log_warning_errno(SYNTHETIC_ERRNO(EKEYREJECTED), "%s skipped.", unit_name);
-        }
-
-        r = create_edit_temp_file(new_path, fragment_path, &tmp_path);
-        if (r < 0)
-                return r;
-
-        *ret_new_path = TAKE_PTR(new_path);
-        *ret_tmp_path = TAKE_PTR(tmp_path);
-
-        return 0;
-}
-
-static int run_editor(char **paths) {
-        int r;
-
-        assert(paths);
-
-        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) {
-                char **editor_args = NULL, **tmp_path, **original_path;
-                size_t n_editor_args = 0, i = 1, argc;
-                const char **args, *editor, *p;
-
-                argc = strv_length(paths)/2 + 1;
-
-                /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
-                 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
-                 * we try to execute well known editors
-                 */
-                editor = getenv("SYSTEMD_EDITOR");
-                if (!editor)
-                        editor = getenv("EDITOR");
-                if (!editor)
-                        editor = getenv("VISUAL");
-
-                if (!isempty(editor)) {
-                        editor_args = strv_split(editor, WHITESPACE);
-                        if (!editor_args) {
-                                (void) log_oom();
-                                _exit(EXIT_FAILURE);
-                        }
-                        n_editor_args = strv_length(editor_args);
-                        argc += n_editor_args - 1;
-                }
-
-                args = newa(const char*, argc + 1);
-
-                if (n_editor_args > 0) {
-                        args[0] = editor_args[0];
-                        for (; i < n_editor_args; i++)
-                                args[i] = editor_args[i];
-                }
-
-                STRV_FOREACH_PAIR(original_path, tmp_path, paths)
-                        args[i++] = *tmp_path;
-                args[i] = NULL;
-
-                if (n_editor_args > 0)
-                        execvp(args[0], (char* const*) args);
-
-                FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
-                        args[0] = p;
-                        execvp(p, (char* const*) args);
-                        /* We do not fail if the editor doesn't exist
-                         * because we want to try each one of them before
-                         * failing.
-                         */
-                        if (errno != ENOENT) {
-                                log_error_errno(errno, "Failed to execute %s: %m", editor);
-                                _exit(EXIT_FAILURE);
-                        }
-                }
-
-                log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
-                _exit(EXIT_FAILURE);
-        }
-
-        return 0;
-}
-
-static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
-        _cleanup_(lookup_paths_free) LookupPaths lp = {};
-        char **name;
-        int r;
-
-        assert(names);
-        assert(paths);
-
-        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(name, names) {
-                _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, 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;
-
-                if (r == 0) {
-                        assert(!path);
-
-                        if (!arg_force) {
-                                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;
-                        }
-
-                        /* Create a new unit from scratch */
-                        unit_name = *name;
-                        r = unit_file_create_new(&lp, unit_name,
-                                                 arg_full ? NULL : ".d/override.conf",
-                                                 &new_path, &tmp_path);
-                } else {
-                        assert(path);
-
-                        unit_name = basename(path);
-                        /* We follow unit aliases, but we need to propagate the instance */
-                        if (unit_name_is_valid(*name, UNIT_NAME_INSTANCE) &&
-                            unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
-                                _cleanup_free_ char *instance = NULL;
-
-                                r = unit_name_to_instance(*name, &instance);
-                                if (r < 0)
-                                        return r;
-
-                                r = unit_name_replace_instance(unit_name, instance, &tmp_name);
-                                if (r < 0)
-                                        return r;
-
-                                unit_name = tmp_name;
-                        }
-
-                        if (arg_full)
-                                r = unit_file_create_copy(&lp, unit_name, path, &new_path, &tmp_path);
-                        else
-                                r = unit_file_create_new(&lp, unit_name, ".d/override.conf", &new_path, &tmp_path);
-                }
-                if (r < 0)
-                        return r;
-
-                r = strv_push_pair(paths, new_path, tmp_path);
-                if (r < 0)
-                        return log_oom();
-
-                new_path = tmp_path = NULL;
-        }
-
-        return 0;
-}
-
-static int edit(int argc, char *argv[], void *userdata) {
-        _cleanup_(lookup_paths_free) LookupPaths lp = {};
-        _cleanup_strv_free_ char **names = NULL;
-        _cleanup_strv_free_ char **paths = NULL;
-        char **original, **tmp;
-        sd_bus *bus;
-        int r;
-
-        if (!on_tty())
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units if not on a tty.");
-
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely.");
-
-        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine unit paths: %m");
-
-        r = mac_selinux_init();
-        if (r < 0)
-                return r;
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        STRV_FOREACH(tmp, names) {
-                r = unit_is_masked(bus, &lp, *tmp);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit %s: unit is masked.", *tmp);
-        }
-
-        r = find_paths_to_edit(bus, names, &paths);
-        if (r < 0)
-                return r;
-
-        if (strv_isempty(paths))
-                return -ENOENT;
-
-        r = run_editor(paths);
-        if (r < 0)
-                goto end;
-
-        STRV_FOREACH_PAIR(original, tmp, paths) {
-                /* If the temporary file is empty we ignore it.
-                 * This allows the user to cancel the modification.
-                 */
-                if (null_or_empty_path(*tmp)) {
-                        log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
-                        continue;
-                }
-
-                r = rename(*tmp, *original);
-                if (r < 0) {
-                        r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
-                        goto end;
-                }
-        }
-
-        r = 0;
-
-        if (!arg_no_reload && !install_client_side())
-                r = daemon_reload(argc, argv, userdata);
-
-end:
-        STRV_FOREACH_PAIR(original, tmp, paths) {
-                (void) unlink(*tmp);
-
-                /* Removing empty dropin dirs */
-                if (!arg_full) {
-                        _cleanup_free_ char *dir;
-
-                        dir = dirname_malloc(*original);
-                        if (!dir)
-                                return log_oom();
+#include "bus-util.h"
+#include "install.h"
+#include "main-func.h"
+#include "output-mode.h"
+#include "pager.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "rlimit-util.h"
+#include "sigbus.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "systemctl-add-dependency.h"
+#include "systemctl-cancel-job.h"
+#include "systemctl-clean-or-freeze.h"
+#include "systemctl-compat-halt.h"
+#include "systemctl-compat-runlevel.h"
+#include "systemctl-compat-shutdown.h"
+#include "systemctl-compat-telinit.h"
+#include "systemctl-daemon-reload.h"
+#include "systemctl-edit.h"
+#include "systemctl-enable.h"
+#include "systemctl-is-active.h"
+#include "systemctl-is-enabled.h"
+#include "systemctl-is-system-running.h"
+#include "systemctl-kill.h"
+#include "systemctl-list-dependencies.h"
+#include "systemctl-list-jobs.h"
+#include "systemctl-list-machines.h"
+#include "systemctl-list-unit-files.h"
+#include "systemctl-list-units.h"
+#include "systemctl-log-setting.h"
+#include "systemctl-logind.h"
+#include "systemctl-preset-all.h"
+#include "systemctl-reset-failed.h"
+#include "systemctl-service-watchdogs.h"
+#include "systemctl-set-default.h"
+#include "systemctl-set-environment.h"
+#include "systemctl-set-property.h"
+#include "systemctl-show.h"
+#include "systemctl-start-special.h"
+#include "systemctl-start-unit.h"
+#include "systemctl-switch-root.h"
+#include "systemctl-sysv-compat.h"
+#include "systemctl-trivial-method.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+#include "time-util.h"
+#include "verbs.h"
+#include "virt.h"
 
-                        /* no need to check if the dir is empty, rmdir
-                         * does nothing if it is not the case.
-                         */
-                        (void) rmdir(dir);
-                }
-        }
+char **arg_types = NULL;
+char **arg_states = NULL;
+char **arg_properties = NULL;
+bool arg_all = false;
+enum dependency arg_dependency = DEPENDENCY_FORWARD;
+const char *arg_job_mode = "replace";
+UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
+bool arg_wait = false;
+bool arg_no_block = false;
+bool arg_no_legend = false;
+PagerFlags arg_pager_flags = 0;
+bool arg_no_wtmp = false;
+bool arg_no_sync = false;
+bool arg_no_wall = false;
+bool arg_no_reload = false;
+bool arg_value = false;
+bool arg_show_types = false;
+bool arg_ignore_inhibitors = false;
+bool arg_dry_run = false;
+bool arg_quiet = false;
+bool arg_full = false;
+bool arg_recursive = false;
+bool arg_with_dependencies = false;
+bool arg_show_transaction = false;
+int arg_force = 0;
+bool arg_ask_password = false;
+bool arg_runtime = false;
+UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
+char **arg_wall = NULL;
+const char *arg_kill_who = NULL;
+int arg_signal = SIGTERM;
+char *arg_root = NULL;
+usec_t arg_when = 0;
+const char *arg_reboot_argument = NULL;
+enum action arg_action = ACTION_SYSTEMCTL;
+BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+const char *arg_host = NULL;
+unsigned arg_lines = 10;
+OutputMode arg_output = OUTPUT_SHORT;
+bool arg_plain = false;
+bool arg_firmware_setup = false;
+usec_t arg_boot_loader_menu = USEC_INFINITY;
+const char *arg_boot_loader_entry = NULL;
+bool arg_now = false;
+bool arg_jobs_before = false;
+bool arg_jobs_after = false;
+char **arg_clean_what = NULL;
+TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
 
-        return r;
-}
+STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
 
 static int systemctl_help(void) {
         _cleanup_free_ char *link = NULL;
@@ -7948,117 +293,6 @@ static int systemctl_help(void) {
         return 0;
 }
 
-static int halt_help(void) {
-        _cleanup_free_ char *link = NULL;
-        int r;
-
-        r = terminal_urlify_man("halt", "8", &link);
-        if (r < 0)
-                return log_oom();
-
-        printf("%s [OPTIONS...]%s\n"
-               "\n%s%s the system.%s\n"
-               "\nOptions:\n"
-               "     --help      Show this help\n"
-               "     --halt      Halt the machine\n"
-               "  -p --poweroff  Switch off the machine\n"
-               "     --reboot    Reboot the machine\n"
-               "  -f --force     Force immediate halt/power-off/reboot\n"
-               "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
-               "  -d --no-wtmp   Don't write wtmp record\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
-               "\nSee the %s for details.\n"
-               , program_invocation_short_name
-               , arg_action == ACTION_REBOOT   ? " [ARG]" : ""
-               , ansi_highlight()
-               , arg_action == ACTION_REBOOT   ? "Reboot" :
-                 arg_action == ACTION_POWEROFF ? "Power off" :
-                                                 "Halt"
-               , ansi_normal()
-               , link
-        );
-
-        return 0;
-}
-
-static int shutdown_help(void) {
-        _cleanup_free_ char *link = NULL;
-        int r;
-
-        r = terminal_urlify_man("shutdown", "8", &link);
-        if (r < 0)
-                return log_oom();
-
-        printf("%s [OPTIONS...] [TIME] [WALL...]\n"
-               "\n%sShut down the system.%s\n"
-               "\nOptions:\n"
-               "     --help      Show this help\n"
-               "  -H --halt      Halt the machine\n"
-               "  -P --poweroff  Power-off the machine\n"
-               "  -r --reboot    Reboot the machine\n"
-               "  -h             Equivalent to --poweroff, overridden by --halt\n"
-               "  -k             Don't halt/power-off/reboot, just send warnings\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
-               "  -c             Cancel a pending shutdown\n"
-               "\nSee the %s for details.\n"
-               , program_invocation_short_name
-               , ansi_highlight(), ansi_normal()
-               , link
-        );
-
-        return 0;
-}
-
-static int telinit_help(void) {
-        _cleanup_free_ char *link = NULL;
-        int r;
-
-        r = terminal_urlify_man("telinit", "8", &link);
-        if (r < 0)
-                return log_oom();
-
-        printf("%s [OPTIONS...] COMMAND\n\n"
-               "%sSend control commands to the init daemon.%s\n"
-               "\nCommands:\n"
-               "  0              Power-off the machine\n"
-               "  6              Reboot the machine\n"
-               "  2, 3, 4, 5     Start runlevelX.target unit\n"
-               "  1, s, S        Enter rescue mode\n"
-               "  q, Q           Reload init daemon configuration\n"
-               "  u, U           Reexecute init daemon\n"
-               "\nOptions:\n"
-               "     --help      Show this help\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
-               "\nSee the %s for details.\n"
-               , program_invocation_short_name
-               , ansi_highlight(), ansi_normal()
-               , link
-        );
-
-        return 0;
-}
-
-static int runlevel_help(void) {
-        _cleanup_free_ char *link = NULL;
-        int r;
-
-        r = terminal_urlify_man("runlevel", "8", &link);
-        if (r < 0)
-                return log_oom();
-
-        printf("%s [OPTIONS...]\n"
-               "\n%sPrints the previous and current runlevel of the init system.%s\n"
-               "\nOptions:\n"
-               "     --help      Show this help\n"
-               "\nSee the %s for details.\n"
-               , program_invocation_short_name
-               , ansi_highlight(), ansi_normal()
-               , link
-        );
-
-        return 0;
-}
-
 static void help_types(void) {
         if (!arg_no_legend)
                 puts("Available unit types:");
@@ -8113,39 +347,15 @@ static void help_states(void) {
 
         if (!arg_no_legend)
                 puts("\nAvailable swap unit substates:");
-        DUMP_STRING_TABLE(swap_state, SwapState, _SWAP_STATE_MAX);
-
-        if (!arg_no_legend)
-                puts("\nAvailable target unit substates:");
-        DUMP_STRING_TABLE(target_state, TargetState, _TARGET_STATE_MAX);
-
-        if (!arg_no_legend)
-                puts("\nAvailable timer unit substates:");
-        DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX);
-}
-
-static int help_boot_loader_entry(void) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_strv_free_ char **l = NULL;
-        sd_bus *bus;
-        char **i;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
-        if (r < 0)
-                return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
-
-        if (strv_isempty(l))
-                return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
+        DUMP_STRING_TABLE(swap_state, SwapState, _SWAP_STATE_MAX);
 
-        STRV_FOREACH(i, l)
-                puts(*i);
+        if (!arg_no_legend)
+                puts("\nAvailable target unit substates:");
+        DUMP_STRING_TABLE(target_state, TargetState, _TARGET_STATE_MAX);
 
-        return 0;
+        if (!arg_no_legend)
+                puts("\nAvailable timer unit substates:");
+        DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX);
 }
 
 static int systemctl_parse_argv(int argc, char *argv[]) {
@@ -8250,7 +460,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
+        /* 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:P:alqfs:H:M:n:o:iTr.::", options, NULL)) >= 0)
@@ -8290,10 +500,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         continue;
                                 }
 
-                                /* It's much nicer to use --state= for
-                                 * load states, but let's support this
-                                 * in --types= too for compatibility
-                                 * with old versions */
+                                /* It's much nicer to use --state= for load states, but let's support this in
+                                 * --types= too for compatibility with old versions */
                                 if (unit_load_state_from_string(type) >= 0) {
                                         if (strv_consume(&arg_states, TAKE_PTR(type)) < 0)
                                                 return log_oom();
@@ -8521,464 +729,146 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
                 case ARG_BOOT_LOADER_MENU:
 
-                        r = parse_sec(optarg, &arg_boot_loader_menu);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to parse --boot-loader-menu= argument '%s': %m", optarg);
-
-                        break;
-
-                case ARG_BOOT_LOADER_ENTRY:
-
-                        if (streq(optarg, "help")) { /* Yes, this means, "help" is not a valid boot loader entry name we can deal with */
-                                r = help_boot_loader_entry();
-                                if (r < 0)
-                                        return r;
-
-                                return 0;
-                        }
-
-                        arg_boot_loader_entry = empty_to_null(optarg);
-                        break;
-
-                case ARG_STATE: {
-                        const char *p;
-
-                        if (isempty(optarg))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "--state= requires arguments.");
-
-                        for (p = optarg;;) {
-                                _cleanup_free_ char *s = NULL;
-
-                                r = extract_first_word(&p, &s, ",", 0);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to parse state: %s", optarg);
-                                if (r == 0)
-                                        break;
-
-                                if (streq(s, "help")) {
-                                        help_states();
-                                        return 0;
-                                }
-
-                                if (strv_consume(&arg_states, TAKE_PTR(s)) < 0)
-                                        return log_oom();
-                        }
-                        break;
-                }
-
-                case 'r':
-                        if (geteuid() != 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EPERM),
-                                                       "--recursive requires root privileges.");
-
-                        arg_recursive = true;
-                        break;
-
-                case ARG_PRESET_MODE:
-                        if (streq(optarg, "help")) {
-                                DUMP_STRING_TABLE(unit_file_preset_mode, UnitFilePresetMode, _UNIT_FILE_PRESET_MAX);
-                                return 0;
-                        }
-
-                        arg_preset_mode = unit_file_preset_mode_from_string(optarg);
-                        if (arg_preset_mode < 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Failed to parse preset mode: %s.", optarg);
-
-                        break;
-
-                case ARG_NOW:
-                        arg_now = true;
-                        break;
-
-                case ARG_MESSAGE:
-                        if (strv_extend(&arg_wall, optarg) < 0)
-                                return log_oom();
-                        break;
-
-                case 'T':
-                        arg_show_transaction = true;
-                        break;
-
-                case ARG_WITH_DEPENDENCIES:
-                        arg_with_dependencies = true;
-                        break;
-
-                case ARG_WHAT: {
-                        const char *p;
-
-                        if (isempty(optarg))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--what= requires arguments.");
-
-                        for (p = optarg;;) {
-                                _cleanup_free_ char *k = NULL;
-
-                                r = extract_first_word(&p, &k, ",", 0);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to parse directory type: %s", optarg);
-                                if (r == 0)
-                                        break;
-
-                                if (streq(k, "help")) {
-                                        puts("runtime\n"
-                                             "state\n"
-                                             "cache\n"
-                                             "logs\n"
-                                             "configuration");
-                                        return 0;
-                                }
-
-                                r = strv_consume(&arg_clean_what, TAKE_PTR(k));
-                                if (r < 0)
-                                        return log_oom();
-                        }
-
-                        break;
-                }
-
-                case ARG_REBOOT_ARG:
-                        arg_reboot_argument = optarg;
-                        break;
-
-                case ARG_TIMESTAMP_STYLE:
-                        if (streq(optarg, "help")) {
-                                DUMP_STRING_TABLE(timestamp_style, TimestampStyle, _TIMESTAMP_STYLE_MAX);
-                                return 0;
-                        }
-
-                        arg_timestamp_style = timestamp_style_from_string(optarg);
-                        if (arg_timestamp_style < 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Invalid value: %s.", optarg);
-
-                        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;
-
-                default:
-                        assert_not_reached("Unhandled option");
-                }
-
-        if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Cannot access user instance remotely.");
-
-        if (arg_wait && arg_no_block)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "--wait may not be combined with --no-block.");
-
-        return 1;
-}
-
-static int halt_parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_HELP = 0x100,
-                ARG_HALT,
-                ARG_REBOOT,
-                ARG_NO_WALL
-        };
-
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, ARG_HELP    },
-                { "halt",      no_argument,       NULL, ARG_HALT    },
-                { "poweroff",  no_argument,       NULL, 'p'         },
-                { "reboot",    no_argument,       NULL, ARG_REBOOT  },
-                { "force",     no_argument,       NULL, 'f'         },
-                { "wtmp-only", no_argument,       NULL, 'w'         },
-                { "no-wtmp",   no_argument,       NULL, 'd'         },
-                { "no-sync",   no_argument,       NULL, 'n'         },
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                {}
-        };
-
-        int c, r, runlevel;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        if (utmp_get_runlevel(&runlevel, NULL) >= 0)
-                if (IN_SET(runlevel, '0', '6'))
-                        arg_force = 2;
-
-        while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
-                switch (c) {
-
-                case ARG_HELP:
-                        return halt_help();
-
-                case ARG_HALT:
-                        arg_action = ACTION_HALT;
-                        break;
-
-                case 'p':
-                        if (arg_action != ACTION_REBOOT)
-                                arg_action = ACTION_POWEROFF;
-                        break;
-
-                case ARG_REBOOT:
-                        arg_action = ACTION_REBOOT;
-                        break;
-
-                case 'f':
-                        arg_force = 2;
-                        break;
-
-                case 'w':
-                        arg_dry_run = true;
-                        break;
-
-                case 'd':
-                        arg_no_wtmp = true;
-                        break;
-
-                case 'n':
-                        arg_no_sync = true;
-                        break;
-
-                case ARG_NO_WALL:
-                        arg_no_wall = true;
-                        break;
-
-                case 'i':
-                case 'h':
-                        /* Compatibility nops */
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unhandled option");
-                }
-
-        if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
-                r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
-                if (r < 0)
-                        return r;
-        } else if (optind < argc)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Too many arguments.");
-
-        return 1;
-}
-
-static int shutdown_parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_HELP = 0x100,
-                ARG_NO_WALL
-        };
-
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, ARG_HELP    },
-                { "halt",      no_argument,       NULL, 'H'         },
-                { "poweroff",  no_argument,       NULL, 'P'         },
-                { "reboot",    no_argument,       NULL, 'r'         },
-                { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                {}
-        };
-
-        char **wall = NULL;
-        int c, r;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
-                switch (c) {
-
-                case ARG_HELP:
-                        return shutdown_help();
-
-                case 'H':
-                        arg_action = ACTION_HALT;
-                        break;
-
-                case 'P':
-                        arg_action = ACTION_POWEROFF;
-                        break;
-
-                case 'r':
-                        if (kexec_loaded())
-                                arg_action = ACTION_KEXEC;
-                        else
-                                arg_action = ACTION_REBOOT;
-                        break;
-
-                case 'K':
-                        arg_action = ACTION_KEXEC;
-                        break;
-
-                case 'h':
-                        if (arg_action != ACTION_HALT)
-                                arg_action = ACTION_POWEROFF;
-                        break;
-
-                case 'k':
-                        arg_dry_run = true;
-                        break;
+                        r = parse_sec(optarg, &arg_boot_loader_menu);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --boot-loader-menu= argument '%s': %m", optarg);
 
-                case ARG_NO_WALL:
-                        arg_no_wall = true;
                         break;
 
-                case 'a':
-                case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
-                case 'f':
-                case 'F':
-                        /* Compatibility nops */
-                        break;
+                case ARG_BOOT_LOADER_ENTRY:
 
-                case 'c':
-                        arg_action = ACTION_CANCEL_SHUTDOWN;
-                        break;
+                        if (streq(optarg, "help")) { /* Yes, this means, "help" is not a valid boot loader entry name we can deal with */
+                                r = help_boot_loader_entry();
+                                if (r < 0)
+                                        return r;
 
-                case '?':
-                        return -EINVAL;
+                                return 0;
+                        }
 
-                default:
-                        assert_not_reached("Unhandled option");
-                }
+                        arg_boot_loader_entry = empty_to_null(optarg);
+                        break;
 
-        if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
-                r = parse_shutdown_time_spec(argv[optind], &arg_when);
-                if (r < 0) {
-                        log_error("Failed to parse time specification: %s", argv[optind]);
-                        return r;
-                }
-        } else
-                arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
-
-        if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
-                /* No time argument for shutdown cancel */
-                wall = argv + optind;
-        else if (argc > optind + 1)
-                /* We skip the time argument */
-                wall = argv + optind + 1;
-
-        if (wall) {
-                arg_wall = strv_copy(wall);
-                if (!arg_wall)
-                        return log_oom();
-        }
+                case ARG_STATE: {
+                        const char *p;
 
-        optind = argc;
+                        if (isempty(optarg))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "--state= requires arguments.");
 
-        return 1;
-}
+                        for (p = optarg;;) {
+                                _cleanup_free_ char *s = NULL;
 
-static int telinit_parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_HELP = 0x100,
-                ARG_NO_WALL
-        };
+                                r = extract_first_word(&p, &s, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse state: %s", optarg);
+                                if (r == 0)
+                                        break;
 
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, ARG_HELP    },
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                {}
-        };
+                                if (streq(s, "help")) {
+                                        help_states();
+                                        return 0;
+                                }
 
-        static const struct {
-                char from;
-                enum action to;
-        } table[] = {
-                { '0', ACTION_POWEROFF },
-                { '6', ACTION_REBOOT },
-                { '1', ACTION_RESCUE },
-                { '2', ACTION_RUNLEVEL2 },
-                { '3', ACTION_RUNLEVEL3 },
-                { '4', ACTION_RUNLEVEL4 },
-                { '5', ACTION_RUNLEVEL5 },
-                { 's', ACTION_RESCUE },
-                { 'S', ACTION_RESCUE },
-                { 'q', ACTION_RELOAD },
-                { 'Q', ACTION_RELOAD },
-                { 'u', ACTION_REEXEC },
-                { 'U', ACTION_REEXEC }
-        };
+                                if (strv_consume(&arg_states, TAKE_PTR(s)) < 0)
+                                        return log_oom();
+                        }
+                        break;
+                }
 
-        unsigned i;
-        int c;
+                case 'r':
+                        if (geteuid() != 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+                                                       "--recursive requires root privileges.");
 
-        assert(argc >= 0);
-        assert(argv);
+                        arg_recursive = true;
+                        break;
 
-        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
-                switch (c) {
+                case ARG_PRESET_MODE:
+                        if (streq(optarg, "help")) {
+                                DUMP_STRING_TABLE(unit_file_preset_mode, UnitFilePresetMode, _UNIT_FILE_PRESET_MAX);
+                                return 0;
+                        }
 
-                case ARG_HELP:
-                        return telinit_help();
+                        arg_preset_mode = unit_file_preset_mode_from_string(optarg);
+                        if (arg_preset_mode < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Failed to parse preset mode: %s.", optarg);
 
-                case ARG_NO_WALL:
-                        arg_no_wall = true;
                         break;
 
-                case '?':
-                        return -EINVAL;
+                case ARG_NOW:
+                        arg_now = true;
+                        break;
 
-                default:
-                        assert_not_reached("Unhandled option");
-                }
+                case ARG_MESSAGE:
+                        if (strv_extend(&arg_wall, optarg) < 0)
+                                return log_oom();
+                        break;
 
-        if (optind >= argc)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s: required argument missing.",
-                                       program_invocation_short_name);
+                case 'T':
+                        arg_show_transaction = true;
+                        break;
 
-        if (optind + 1 < argc)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Too many arguments.");
+                case ARG_WITH_DEPENDENCIES:
+                        arg_with_dependencies = true;
+                        break;
 
-        if (strlen(argv[optind]) != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Expected single character argument.");
+                case ARG_WHAT: {
+                        const char *p;
 
-        for (i = 0; i < ELEMENTSOF(table); i++)
-                if (table[i].from == argv[optind][0])
-                        break;
+                        if (isempty(optarg))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--what= requires arguments.");
 
-        if (i >= ELEMENTSOF(table))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Unknown command '%s'.", argv[optind]);
+                        for (p = optarg;;) {
+                                _cleanup_free_ char *k = NULL;
 
-        arg_action = table[i].to;
+                                r = extract_first_word(&p, &k, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse directory type: %s", optarg);
+                                if (r == 0)
+                                        break;
 
-        optind++;
+                                if (streq(k, "help")) {
+                                        puts("runtime\n"
+                                             "state\n"
+                                             "cache\n"
+                                             "logs\n"
+                                             "configuration");
+                                        return 0;
+                                }
 
-        return 1;
-}
+                                r = strv_consume(&arg_clean_what, TAKE_PTR(k));
+                                if (r < 0)
+                                        return log_oom();
+                        }
 
-static int runlevel_parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_HELP = 0x100,
-        };
+                        break;
+                }
 
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, ARG_HELP    },
-                {}
-        };
+                case ARG_REBOOT_ARG:
+                        arg_reboot_argument = optarg;
+                        break;
 
-        int c;
+                case ARG_TIMESTAMP_STYLE:
+                        if (streq(optarg, "help")) {
+                                DUMP_STRING_TABLE(timestamp_style, TimestampStyle, _TIMESTAMP_STYLE_MAX);
+                                return 0;
+                        }
 
-        assert(argc >= 0);
-        assert(argv);
+                        arg_timestamp_style = timestamp_style_from_string(optarg);
+                        if (arg_timestamp_style < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid value: %s.", optarg);
 
-        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
-                switch (c) {
+                        break;
 
-                case ARG_HELP:
-                        return runlevel_help();
+                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;
@@ -8987,9 +877,13 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option");
                 }
 
-        if (optind < argc)
+        if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Cannot access user instance remotely.");
+
+        if (arg_wait && arg_no_block)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Too many arguments.");
+                                       "--wait may not be combined with --no-block.");
 
         return 1;
 }
@@ -9021,8 +915,8 @@ static int parse_argv(int argc, char *argv[]) {
 
                 } else if (strstr(program_invocation_short_name, "init")) {
 
-                        /* Matches invocations as "init" as well as "telinit", which are synonymous when run as PID !=
-                         * 1 on SysV.
+                        /* Matches invocations as "init" as well as "telinit", which are synonymous when run
+                         * as PID != 1 on SysV.
                          *
                          * On SysV "telinit" was the official command to communicate with PID 1, but "init" would
                          * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still,
@@ -9058,24 +952,6 @@ static int parse_argv(int argc, char *argv[]) {
         return systemctl_parse_argv(argc, argv);
 }
 
-#if HAVE_SYSV_COMPAT
-_pure_ static int action_to_runlevel(void) {
-        static const char table[_ACTION_MAX] = {
-                [ACTION_HALT] =      '0',
-                [ACTION_POWEROFF] =  '0',
-                [ACTION_REBOOT] =    '6',
-                [ACTION_RUNLEVEL2] = '2',
-                [ACTION_RUNLEVEL3] = '3',
-                [ACTION_RUNLEVEL4] = '4',
-                [ACTION_RUNLEVEL5] = '5',
-                [ACTION_RESCUE] =    '1'
-        };
-
-        assert(arg_action >= 0 && arg_action < _ACTION_MAX);
-        return table[arg_action];
-}
-#endif
-
 static int systemctl_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
                 { "list-units",            VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units },
@@ -9165,230 +1041,6 @@ static int systemctl_main(int argc, char *argv[]) {
         return dispatch_verb(argc, argv, verbs, NULL);
 }
 
-static int reload_with_fallback(void) {
-        /* First, try systemd via D-Bus. */
-        if (daemon_reload(0, NULL, NULL) >= 0)
-                return 0;
-
-        /* Nothing else worked, so let's try signals */
-        assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
-
-        if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
-                return log_error_errno(errno, "kill() failed: %m");
-
-        return 0;
-}
-
-static int start_with_fallback(void) {
-        /* First, try systemd via D-Bus. */
-        if (start_unit(0, NULL, NULL) == 0)
-                return 0;
-
-#if HAVE_SYSV_COMPAT
-        /* Nothing else worked, so let's try /dev/initctl */
-        if (talk_initctl(action_to_runlevel()) > 0)
-                return 0;
-#endif
-
-        return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                               "Failed to talk to init daemon.");
-}
-
-static int halt_now(enum action a) {
-        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
-         * synced explicitly in advance. */
-        if (!arg_no_sync && !arg_dry_run)
-                (void) sync();
-
-        /* Make sure C-A-D is handled by the kernel from this point on... */
-        if (!arg_dry_run)
-                (void) reboot(RB_ENABLE_CAD);
-
-        switch (a) {
-
-        case ACTION_HALT:
-                if (!arg_quiet)
-                        log_info("Halting.");
-                if (arg_dry_run)
-                        return 0;
-                (void) reboot(RB_HALT_SYSTEM);
-                return -errno;
-
-        case ACTION_POWEROFF:
-                if (!arg_quiet)
-                        log_info("Powering off.");
-                if (arg_dry_run)
-                        return 0;
-                (void) reboot(RB_POWER_OFF);
-                return -errno;
-
-        case ACTION_KEXEC:
-        case ACTION_REBOOT:
-                return reboot_with_parameter(REBOOT_FALLBACK |
-                                             (arg_quiet ? 0 : REBOOT_LOG) |
-                                             (arg_dry_run ? REBOOT_DRY_RUN : 0));
-
-        default:
-                assert_not_reached("Unknown action.");
-        }
-}
-
-static int logind_schedule_shutdown(void) {
-
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        char date[FORMAT_TIMESTAMP_MAX];
-        const char *action;
-        const char *log_action;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        switch (arg_action) {
-        case ACTION_HALT:
-                action = "halt";
-                log_action = "Shutdown";
-                break;
-        case ACTION_POWEROFF:
-                action = "poweroff";
-                log_action = "Shutdown";
-                break;
-        case ACTION_KEXEC:
-                action = "kexec";
-                log_action = "Reboot via kexec";
-                break;
-        case ACTION_EXIT:
-                action = "exit";
-                log_action = "Shutdown";
-                break;
-        case ACTION_REBOOT:
-        default:
-                action = "reboot";
-                log_action = "Reboot";
-                break;
-        }
-
-        if (arg_dry_run)
-                action = strjoina("dry-", action);
-
-        (void) logind_set_wall_message();
-
-        r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
-        if (r < 0)
-                return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
-
-        if (!arg_quiet)
-                log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
-        return 0;
-#else
-        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
-                               "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
-#endif
-}
-
-static int halt_main(void) {
-        int r;
-
-        r = logind_check_inhibitors(arg_action);
-        if (r < 0)
-                return r;
-
-        /* Delayed shutdown requested, and was successful */
-        if (arg_when > 0 && logind_schedule_shutdown() == 0)
-                return 0;
-        /* no delay, or logind failed or is not at all available */
-
-        if (geteuid() != 0) {
-                if (arg_dry_run || arg_force > 0) {
-                        (void) must_be_root();
-                        return -EPERM;
-                }
-
-                /* Try logind if we are a normal user and no special
-                 * mode applies. Maybe polkit allows us to shutdown
-                 * the machine. */
-                if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
-                        r = logind_reboot(arg_action);
-                        if (r >= 0)
-                                return r;
-                        if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
-                                /* requested operation is not
-                                 * supported on the local system or
-                                 * already in progress */
-                                return r;
-                        /* on all other errors, try low-level operation */
-                }
-        }
-
-        /* In order to minimize the difference between operation with and
-         * without logind, we explicitly enable non-blocking mode for this,
-         * as logind's shutdown operations are always non-blocking. */
-        arg_no_block = true;
-
-        if (!arg_dry_run && !arg_force)
-                return start_with_fallback();
-
-        assert(geteuid() == 0);
-
-        if (!arg_no_wtmp) {
-                if (sd_booted() > 0)
-                        log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
-                else {
-                        r = utmp_put_shutdown();
-                        if (r < 0)
-                                log_warning_errno(r, "Failed to write utmp record: %m");
-                }
-        }
-
-        if (arg_dry_run)
-                return 0;
-
-        r = halt_now(arg_action);
-        return log_error_errno(r, "Failed to reboot: %m");
-}
-
-static int runlevel_main(void) {
-        int r, runlevel, previous;
-
-        r = utmp_get_runlevel(&runlevel, &previous);
-        if (r < 0) {
-                puts("unknown");
-                return r;
-        }
-
-        printf("%c %c\n",
-               previous <= 0 ? 'N' : previous,
-               runlevel <= 0 ? 'N' : runlevel);
-
-        return 0;
-}
-
-static int logind_cancel_shutdown(void) {
-#if ENABLE_LOGIND
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus;
-        int r;
-
-        r = acquire_bus(BUS_FULL, &bus);
-        if (r < 0)
-                return r;
-
-        (void) logind_set_wall_message();
-
-        r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
-        if (r < 0)
-                return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
-
-        return 0;
-#else
-        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
-                               "Not compiled with logind support, cannot cancel scheduled shutdowns.");
-#endif
-}
-
 static int run(int argc, char *argv[]) {
         int r;
 
@@ -9401,11 +1053,6 @@ static int run(int argc, char *argv[]) {
 
         sigbus_install();
 
-        /* Explicitly not on_tty() to avoid setting cached value.
-         * This becomes relevant for piping output which might be
-         * ellipsized. */
-        original_stdout_is_tty = isatty(STDOUT_FILENO);
-
         r = parse_argv(argc, argv);
         if (r <= 0)
                 goto finish;
@@ -9417,8 +1064,7 @@ static int run(int argc, char *argv[]) {
                 goto finish;
         }
 
-        /* systemctl_main() will print an error message for the bus
-         * connection, but only if it needs to */
+        /* systemctl_main() will print an error message for the bus connection, but only if it needs to */
 
         switch (arg_action) {
 
@@ -9426,9 +1072,8 @@ static int run(int argc, char *argv[]) {
                 r = systemctl_main(argc, argv);
                 break;
 
-        /* Legacy command aliases set arg_action. They provide some fallbacks,
-         * e.g. to tell sysvinit to reboot after you have installed systemd
-         * binaries. */
+        /* Legacy command aliases set arg_action. They provide some fallbacks, e.g. to tell sysvinit to
+         * reboot after you have installed systemd binaries. */
 
         case ACTION_HALT:
         case ACTION_POWEROFF:
@@ -9465,8 +1110,8 @@ static int run(int argc, char *argv[]) {
         case ACTION_SUSPEND_THEN_HIBERNATE:
         case ACTION_EMERGENCY:
         case ACTION_DEFAULT:
-                /* systemctl verbs with no equivalent in the legacy commands.
-                 * These cannot appear in arg_action.  Fall through. */
+                /* systemctl verbs with no equivalent in the legacy commands.  These cannot appear in
+                 * arg_action.  Fall through. */
 
         case _ACTION_INVALID:
         default:
diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h
new file mode 100644 (file)
index 0000000..079c108
--- /dev/null
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "bus-util.h"
+#include "install.h"
+#include "output-mode.h"
+#include "pager.h"
+
+enum action {
+        ACTION_SYSTEMCTL,
+        ACTION_HALT,
+        ACTION_POWEROFF,
+        ACTION_REBOOT,
+        ACTION_KEXEC,
+        ACTION_EXIT,
+        ACTION_SUSPEND,
+        ACTION_HIBERNATE,
+        ACTION_HYBRID_SLEEP,
+        ACTION_SUSPEND_THEN_HIBERNATE,
+        ACTION_RUNLEVEL2,
+        ACTION_RUNLEVEL3,
+        ACTION_RUNLEVEL4,
+        ACTION_RUNLEVEL5,
+        ACTION_RESCUE,
+        ACTION_EMERGENCY,
+        ACTION_DEFAULT,
+        ACTION_RELOAD,
+        ACTION_REEXEC,
+        ACTION_RUNLEVEL,
+        ACTION_CANCEL_SHUTDOWN,
+        _ACTION_MAX,
+        _ACTION_INVALID = -1
+};
+
+enum dependency {
+        DEPENDENCY_FORWARD,
+        DEPENDENCY_REVERSE,
+        DEPENDENCY_AFTER,
+        DEPENDENCY_BEFORE,
+        _DEPENDENCY_MAX
+};
+
+extern char **arg_types;
+extern char **arg_states;
+extern char **arg_properties;
+extern bool arg_all;
+extern enum dependency arg_dependency;
+extern const char *arg_job_mode;
+extern UnitFileScope arg_scope;
+extern bool arg_wait;
+extern bool arg_no_block;
+extern bool arg_no_legend;
+extern PagerFlags arg_pager_flags;
+extern bool arg_no_wtmp;
+extern bool arg_no_sync;
+extern bool arg_no_wall;
+extern bool arg_no_reload;
+extern bool arg_value;
+extern bool arg_show_types;
+extern bool arg_ignore_inhibitors;
+extern bool arg_dry_run;
+extern bool arg_quiet;
+extern bool arg_full;
+extern bool arg_recursive;
+extern bool arg_with_dependencies;
+extern bool arg_show_transaction;
+extern int arg_force;
+extern bool arg_ask_password;
+extern bool arg_runtime;
+extern UnitFilePresetMode arg_preset_mode;
+extern char **arg_wall;
+extern const char *arg_kill_who;
+extern int arg_signal;
+extern char *arg_root;
+extern usec_t arg_when;
+extern const char *arg_reboot_argument;
+extern enum action arg_action;
+extern BusTransport arg_transport;
+extern const char *arg_host;
+extern unsigned arg_lines;
+extern OutputMode arg_output;
+extern bool arg_plain;
+extern bool arg_firmware_setup;
+extern usec_t arg_boot_loader_menu;
+extern const char *arg_boot_loader_entry;
+extern bool arg_now;
+extern bool arg_jobs_before;
+extern bool arg_jobs_after;
+extern char **arg_clean_what;
+extern TimestampStyle arg_timestamp_style;
diff --git a/src/systemctl/sysv-compat.c b/src/systemctl/sysv-compat.c
deleted file mode 100644 (file)
index 0283daa..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "fd-util.h"
-#include "initreq.h"
-#include "io-util.h"
-#include "parse-util.h"
-#include "strv.h"
-#include "sysv-compat.h"
-
-#if HAVE_SYSV_COMPAT
-int talk_initctl(char rl) {
-        struct init_request request;
-        _cleanup_close_ int fd = -1;
-        const char *p;
-        int r;
-
-        /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this
-         * system, and > 0 on success. */
-
-        if (rl == 0)
-                return 0;
-
-        FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
-                fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
-                if (fd >= 0 || errno != ENOENT)
-                        break;
-        }
-        if (fd < 0) {
-                if (errno == ENOENT)
-                        return 0;
-
-                return log_error_errno(errno, "Failed to open initctl fifo: %m");
-        }
-
-        request = (struct init_request) {
-                .magic = INIT_MAGIC,
-                .sleeptime = 0,
-                .cmd = INIT_CMD_RUNLVL,
-                .runlevel = rl,
-        };
-
-        r = loop_write(fd, &request, sizeof(request), false);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write to %s: %m", p);
-
-        return 1;
-}
-#endif
-
-int parse_shutdown_time_spec(const char *t, usec_t *ret) {
-        assert(t);
-        assert(ret);
-
-        if (streq(t, "now"))
-                *ret = 0;
-        else if (!strchr(t, ':')) {
-                uint64_t u;
-
-                if (safe_atou64(t, &u) < 0)
-                        return -EINVAL;
-
-                *ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
-        } else {
-                char *e = NULL;
-                long hour, minute;
-                struct tm tm = {};
-                time_t s;
-                usec_t n;
-
-                errno = 0;
-                hour = strtol(t, &e, 10);
-                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
-                        return -EINVAL;
-
-                minute = strtol(e+1, &e, 10);
-                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
-                        return -EINVAL;
-
-                n = now(CLOCK_REALTIME);
-                s = (time_t) (n / USEC_PER_SEC);
-
-                assert_se(localtime_r(&s, &tm));
-
-                tm.tm_hour = (int) hour;
-                tm.tm_min = (int) minute;
-                tm.tm_sec = 0;
-
-                s = mktime(&tm);
-                assert(s >= 0);
-
-                *ret = (usec_t) s * USEC_PER_SEC;
-
-                while (*ret <= n)
-                        *ret += USEC_PER_DAY;
-        }
-
-        return 0;
-}
index dc96bfa68176aa05f2c62cae93016358e8b46d8f..3a53c3d27da1419cbf282e787e05d5c6bf03bcb9 100644 (file)
@@ -160,6 +160,8 @@ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t
 int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
 int sd_event_source_get_floating(sd_event_source *s);
 int sd_event_source_set_floating(sd_event_source *s, int b);
+int sd_event_source_get_exit_on_failure(sd_event_source *s);
+int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
 
 /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
index 05f00ed5770c42d039d19305645b4224a91b1c87..eea8c2c900ad8c32aef9aa6c9a88ecee5e471f48 100644 (file)
@@ -127,6 +127,9 @@ _SD_BEGIN_DECLARATIONS;
 #define SD_MESSAGE_OVERMOUNTING           SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
 #define SD_MESSAGE_OVERMOUNTING_STR       SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
 
+#define SD_MESSAGE_UNIT_OOMD_KILL         SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+#define SD_MESSAGE_UNIT_OOMD_KILL_STR     SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+
 #define SD_MESSAGE_UNIT_OUT_OF_MEMORY     SD_ID128_MAKE(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
 #define SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR SD_ID128_MAKE_STR(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
 
index ce7ed36d85a1219bc90fc491d1d0a3367e03becb..e01d960e37b8b69275147049316a9605e49e95b4 100644 (file)
@@ -103,6 +103,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
 int sd_netlink_message_close_container(sd_netlink_message *m);
 
 int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data);
+int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data);
 int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data);
 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data);
 int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret);
index 7349e9fcb9ca535b205fd0969d4407e113188478..b91f32bbf3d353ccb29ef7ecdf1863ed3f9c79ef 100644 (file)
@@ -26,6 +26,7 @@
 #include "strv.h"
 #include "tmpfile-util-label.h"
 #include "uid-range.h"
+#include "user-record.h"
 #include "user-util.h"
 #include "utf8.h"
 #include "util.h"
@@ -83,6 +84,9 @@ static uid_t search_uid = UID_INVALID;
 static UidRange *uid_range = NULL;
 static unsigned n_uid_range = 0;
 
+static UGIDAllocationRange login_defs = {};
+static bool login_defs_need_warning = false;
+
 STATIC_DESTRUCTOR_REGISTER(groups, ordered_hashmap_freep);
 STATIC_DESTRUCTOR_REGISTER(users, ordered_hashmap_freep);
 STATIC_DESTRUCTOR_REGISTER(members, ordered_hashmap_freep);
@@ -104,6 +108,26 @@ static int errno_is_not_exists(int code) {
         return IN_SET(code, 0, ENOENT, ESRCH, EBADF, EPERM);
 }
 
+static void maybe_emit_login_defs_warning(void) {
+        if (!login_defs_need_warning)
+                return;
+
+        if (login_defs.system_alloc_uid_min != SYSTEM_ALLOC_UID_MIN ||
+            login_defs.system_uid_max != SYSTEM_UID_MAX)
+                log_warning("login.defs specifies UID allocation range "UID_FMT"–"UID_FMT
+                            " that is different than the built-in defaults ("UID_FMT"–"UID_FMT")",
+                            login_defs.system_alloc_uid_min, login_defs.system_uid_max,
+                            SYSTEM_ALLOC_UID_MIN, SYSTEM_UID_MAX);
+        if (login_defs.system_alloc_gid_min != SYSTEM_ALLOC_GID_MIN ||
+            login_defs.system_gid_max != SYSTEM_GID_MAX)
+                log_warning("login.defs specifies GID allocation range "GID_FMT"–"GID_FMT
+                            " that is different than the built-in defaults ("GID_FMT"–"GID_FMT")",
+                            login_defs.system_alloc_gid_min, login_defs.system_gid_max,
+                            SYSTEM_ALLOC_GID_MIN, SYSTEM_GID_MAX);
+
+        login_defs_need_warning = false;
+}
+
 static int load_user_database(void) {
         _cleanup_fclose_ FILE *f = NULL;
         const char *passwd_path;
@@ -693,7 +717,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
         ORDERED_HASHMAP_FOREACH(i, todo_gids) {
                 struct sgrp n = {
                         .sg_namp = i->name,
-                        .sg_passwd = (char*) "!!",
+                        .sg_passwd = (char*) "!*",
                 };
 
                 r = putsgent_with_members(&n, gshadow);
@@ -1001,6 +1025,8 @@ static int add_user(Item *i) {
 
         /* And if that didn't work either, let's try to find a free one */
         if (!i->uid_set) {
+                maybe_emit_login_defs_warning();
+
                 for (;;) {
                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
                         if (r < 0)
@@ -1167,6 +1193,8 @@ static int add_group(Item *i) {
 
         /* And if that didn't work either, let's try to find a free one */
         if (!i->gid_set) {
+                maybe_emit_login_defs_warning();
+
                 for (;;) {
                         /* We look for new GIDs in the UID pool! */
                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
@@ -1797,10 +1825,15 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_IMAGE:
+#ifdef STANDALONE
+                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                               "This systemd-sysusers version is compiled without support for --image=.");
+#else
                         r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image);
                         if (r < 0)
                                 return r;
                         break;
+#endif
 
                 case ARG_REPLACE:
                         if (!path_is_absolute(optarg) ||
@@ -1888,9 +1921,11 @@ static int read_config_files(char **args) {
 }
 
 static int run(int argc, char *argv[]) {
+#ifndef STANDALONE
         _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
         _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+#endif
         _cleanup_close_ int lock = -1;
         Item *i;
         int r;
@@ -1910,6 +1945,7 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
+#ifndef STANDALONE
         if (arg_image) {
                 assert(!arg_root);
 
@@ -1926,6 +1962,9 @@ static int run(int argc, char *argv[]) {
                 if (!arg_root)
                         return log_oom();
         }
+#else
+        assert(!arg_image);
+#endif
 
         /* If command line arguments are specified along with --replace, read all
          * configuration files and insert the positional arguments at the specified
@@ -1949,10 +1988,25 @@ static int run(int argc, char *argv[]) {
                 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);
+                /* Default to default range of SYSTEMD_UID_MIN..SYSTEM_UID_MAX. */
+                r = read_login_defs(&login_defs, NULL, arg_root);
                 if (r < 0)
-                        return log_oom();
+                        return log_error_errno(r, "Failed to read %s%s: %m",
+                                               strempty(arg_root), "/etc/login.defs");
+
+                login_defs_need_warning = true;
+
+                /* We pick a range that very conservative: we look at compiled-in maximum and the value in
+                 * /etc/login.defs. That way the uids/gids which we allocate will be interpreted correctly,
+                 * even if /etc/login.defs is removed later. (The bottom bound doesn't matter much, since
+                 * it's only used during allocation, so we use the configured value directly). */
+                uid_t begin = login_defs.system_alloc_uid_min,
+                      end = MIN3((uid_t) SYSTEM_UID_MAX, login_defs.system_uid_max, login_defs.system_gid_max);
+                if (begin < end) {
+                        r = uid_range_add(&uid_range, &n_uid_range, begin, end - begin + 1);
+                        if (r < 0)
+                                return log_oom();
+                }
         }
 
         r = add_implicit();
index 34d64a0f4271cd1c6aed8fee337c05dba47f4229..ac1182e37a21d2903db5dd56a73f6baf150ae54a 100644 (file)
@@ -333,12 +333,16 @@ tests += [
 
         [['src/test/test-parse-util.c'],
          [],
-         []],
+         [libseccomp]],
 
         [['src/test/test-sysctl-util.c'],
          [],
          []],
 
+        [['src/test/test-user-record.c'],
+         [],
+         []],
+
         [['src/test/test-user-util.c'],
          [],
          []],
@@ -800,6 +804,10 @@ tests += [
         [['src/test/test-local-addresses.c'],
          [],
          []],
+
+        [['src/test/test-psi-util.c'],
+         [],
+         []],
 ]
 
 ############################################################
index d209c1304c84097aa2819b89a0ee62cb956d4ca0..b42de612003d518936832eab2efb24ac5f53944c 100644 (file)
@@ -31,6 +31,7 @@
 #include "strv.h"
 #include "tests.h"
 #include "tomoyo-util.h"
+#include "user-record.h"
 #include "user-util.h"
 #include "virt.h"
 
index ead5311705d63c8ac6e8665ce71297f35de98942..b73dc56465617a3336c2aee7c988958a2a12a0ee 100644 (file)
@@ -780,6 +780,20 @@ static void test_dns_name_is_valid_or_address(void) {
         assert_se(dns_name_is_valid_or_address("::1") > 0);
 }
 
+static void test_dns_name_dot_suffixed(void) {
+        log_info("/* %s */", __func__);
+
+        assert_se(dns_name_dot_suffixed("") == 0);
+        assert_se(dns_name_dot_suffixed(".") > 0);
+        assert_se(dns_name_dot_suffixed("foo") == 0);
+        assert_se(dns_name_dot_suffixed("foo.") > 0);
+        assert_se(dns_name_dot_suffixed("foo\\..") > 0);
+        assert_se(dns_name_dot_suffixed("foo\\.") == 0);
+        assert_se(dns_name_dot_suffixed("foo.bar.") > 0);
+        assert_se(dns_name_dot_suffixed("foo.bar\\.\\.\\..") > 0);
+        assert_se(dns_name_dot_suffixed("foo.bar\\.\\.\\.\\.") == 0);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -810,6 +824,7 @@ int main(int argc, char *argv[]) {
         test_dns_name_common_suffix();
         test_dns_name_apply_idna();
         test_dns_name_is_valid_or_address();
+        test_dns_name_dot_suffixed();
 
         return 0;
 }
index f0ffe89729b069617b6d85b611c1ef81a12151d3..4fede158cd075eb9a403d4cd743052b0894e5285 100644 (file)
@@ -10,6 +10,8 @@
 #include "util.h"
 
 static void test_strv_env_delete(void) {
+        log_info("/* %s */", __func__);
+
         _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
 
         a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF");
@@ -30,9 +32,9 @@ static void test_strv_env_delete(void) {
 }
 
 static void test_strv_env_get(void) {
-        char **l;
+        log_info("/* %s */", __func__);
 
-        l = STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
+        char **l = STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
 
         assert_se(streq(strv_env_get(l, "ONE_OR_TWO"), "2"));
         assert_se(streq(strv_env_get(l, "THREE"), "3"));
@@ -40,6 +42,8 @@ static void test_strv_env_get(void) {
 }
 
 static void test_strv_env_unset(void) {
+        log_info("/* %s */", __func__);
+
         _cleanup_strv_free_ char **l = NULL;
 
         l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES");
@@ -53,6 +57,8 @@ static void test_strv_env_unset(void) {
 }
 
 static void test_strv_env_set(void) {
+        log_info("/* %s */", __func__);
+
         _cleanup_strv_free_ char **l = NULL, **r = NULL;
 
         l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES");
@@ -69,6 +75,8 @@ static void test_strv_env_set(void) {
 }
 
 static void test_strv_env_merge(void) {
+        log_info("/* %s */", __func__);
+
         _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL;
 
         a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF");
@@ -97,6 +105,8 @@ static void test_strv_env_merge(void) {
 }
 
 static void test_env_strv_get_n(void) {
+        log_info("/* %s */", __func__);
+
         const char *_env[] = {
                 "FOO=NO NO NO",
                 "FOO=BAR BAR",
@@ -127,6 +137,8 @@ static void test_env_strv_get_n(void) {
 }
 
 static void test_replace_env(bool braceless) {
+        log_info("/* %s(braceless=%s) */", __func__, yes_no(braceless));
+
         const char *env[] = {
                 "FOO=BAR BAR",
                 "BAR=waldo",
@@ -152,6 +164,8 @@ static void test_replace_env(bool braceless) {
 }
 
 static void test_replace_env2(bool extended) {
+        log_info("/* %s(extended=%s) */", __func__, yes_no(extended));
+
         const char *env[] = {
                 "FOO=foo",
                 "BAR=bar",
@@ -180,6 +194,8 @@ static void test_replace_env2(bool extended) {
 }
 
 static void test_replace_env_argv(void) {
+        log_info("/* %s */", __func__);
+
         const char *env[] = {
                 "FOO=BAR BAR",
                 "BAR=waldo",
@@ -230,24 +246,26 @@ static void test_replace_env_argv(void) {
 }
 
 static void test_env_clean(void) {
-        _cleanup_strv_free_ char **e;
-
-        e = strv_new("FOOBAR=WALDO",
-                     "FOOBAR=WALDO",
-                     "FOOBAR",
-                     "F",
-                     "X=",
-                     "F=F",
-                     "=",
-                     "=F",
-                     "",
-                     "0000=000",
-                     "äöüß=abcd",
-                     "abcd=äöüß",
-                     "xyz\n=xyz",
-                     "xyz=xyz\n",
-                     "another=one",
-                     "another=final one");
+        log_info("/* %s */", __func__);
+
+        _cleanup_strv_free_ char **e = strv_new("FOOBAR=WALDO",
+                                                "FOOBAR=WALDO",
+                                                "FOOBAR",
+                                                "F",
+                                                "X=",
+                                                "F=F",
+                                                "=",
+                                                "=F",
+                                                "",
+                                                "0000=000",
+                                                "äöüß=abcd",
+                                                "abcd=äöüß",
+                                                "xyz\n=xyz",
+                                                "xyz=xyz\n",
+                                                "another=one",
+                                                "another=final one",
+                                                "CRLF=\r\n",
+                                                "BASH_FUNC_foo%%=() {  echo foo\n}");
         assert_se(e);
         assert_se(!strv_env_is_valid(e));
         assert_se(strv_env_clean(e) == e);
@@ -256,13 +274,17 @@ static void test_env_clean(void) {
         assert_se(streq(e[0], "FOOBAR=WALDO"));
         assert_se(streq(e[1], "X="));
         assert_se(streq(e[2], "F=F"));
-        assert_se(streq(e[3], "abcd=äöüß"));
-        assert_se(streq(e[4], "xyz=xyz\n"));
-        assert_se(streq(e[5], "another=final one"));
-        assert_se(e[6] == NULL);
+        assert_se(streq(e[3], "0000=000"));
+        assert_se(streq(e[4], "abcd=äöüß"));
+        assert_se(streq(e[5], "xyz=xyz\n"));
+        assert_se(streq(e[6], "another=final one"));
+        assert_se(streq(e[7], "BASH_FUNC_foo%%=() {  echo foo\n}"));
+        assert_se(e[8] == NULL);
 }
 
 static void test_env_name_is_valid(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(env_name_is_valid("test"));
 
         assert_se(!env_name_is_valid(NULL));
@@ -270,19 +292,28 @@ static void test_env_name_is_valid(void) {
         assert_se(!env_name_is_valid("xxx\a"));
         assert_se(!env_name_is_valid("xxx\007b"));
         assert_se(!env_name_is_valid("\007\009"));
-        assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
+        assert_se( env_name_is_valid("5_starting_with_a_number_is_unexpected_but_valid"));
         assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
+        assert_se( env_name_is_valid("BASH_FUNC_foo%%"));
+        assert_se(!env_name_is_valid("with spaces%%"));
+        assert_se(!env_name_is_valid("with\nnewline%%"));
 }
 
 static void test_env_value_is_valid(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(env_value_is_valid(""));
         assert_se(env_value_is_valid("głąb kapuściany"));
         assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
         assert_se(env_value_is_valid("tab\tcharacter"));
         assert_se(env_value_is_valid("new\nline"));
+        assert_se(!env_value_is_valid("Show this?\rNope. Show that!"));
+        assert_se(!env_value_is_valid("new DOS\r\nline"));
 }
 
 static void test_env_assignment_is_valid(void) {
+        log_info("/* %s */", __func__);
+
         assert_se(env_assignment_is_valid("a="));
         assert_se(env_assignment_is_valid("b=głąb kapuściany"));
         assert_se(env_assignment_is_valid("c=\\007\\009\\011"));
@@ -294,9 +325,13 @@ static void test_env_assignment_is_valid(void) {
         assert_se(!env_assignment_is_valid("a b="));
         assert_se(!env_assignment_is_valid("a ="));
         assert_se(!env_assignment_is_valid(" b="));
-        /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
-        assert_se(!env_assignment_is_valid("a.b="));
-        assert_se(!env_assignment_is_valid("a-b="));
+        /* Names with dots and dashes makes those variables inaccessible as bash variables (as the syntax
+         * simply does not allow such variable names, see http://tldp.org/LDP/abs/html/gotchas.html). They
+         * are still valid variables according to POSIX though. */
+        assert_se( env_assignment_is_valid("a.b="));
+        assert_se( env_assignment_is_valid("a-b="));
+        /* Those are not ASCII, so not valid according to POSIX (though zsh does allow unicode variable
+         * names…). */
         assert_se(!env_assignment_is_valid("\007=głąb kapuściany"));
         assert_se(!env_assignment_is_valid("c\009=\007\009\011"));
         assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
index c18d68683e1684a3ef74b3934cefc1b0a1dfac94..0bc2a45c3031cf30e799613a22c31a7b496d3b55 100644 (file)
@@ -36,11 +36,6 @@ static int cld_dumped_to_killed(int code) {
         return code == CLD_DUMPED ? CLD_KILLED : code;
 }
 
-_unused_ static bool is_run_on_travis_ci(void) {
-        /* https://docs.travis-ci.com/user/environment-variables#default-environment-variables */
-        return streq_ptr(getenv("TRAVIS"), "true");
-}
-
 static void wait_for_service_finish(Manager *m, Unit *unit) {
         Service *service = NULL;
         usec_t ts;
@@ -897,7 +892,7 @@ int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
 #if HAS_FEATURE_ADDRESS_SANITIZER
-        if (is_run_on_travis_ci()) {
+        if (strstr_ptr(ci_environment(), "travis")) {
                 log_notice("Running on TravisCI under ASan, skipping, see https://github.com/systemd/systemd/issues/10696");
                 return EXIT_TEST_SKIP;
         }
index 44c74987c58227f631fa40687c53bfc821162eda..5351fdb9e9db048b74cb20c47570332ba6d4af44 100644 (file)
@@ -11,6 +11,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "random-util.h"
+#include "rlimit-util.h"
 #include "serialize.h"
 #include "string-util.h"
 #include "tests.h"
@@ -317,6 +318,100 @@ static void test_read_nr_open(void) {
         log_info("nr-open: %i", read_nr_open());
 }
 
+static size_t validate_fds(
+                bool opened,
+                const int *fds,
+                size_t n_fds) {
+
+        size_t c = 0;
+
+        /* Validates that fds in the specified array are one of the following three:
+         *
+         *  1. < 0 (test is skipped) or
+         *  2. opened (if 'opened' param is true) or
+         *  3. closed (if 'opened' param is false)
+         */
+
+        for (size_t i = 0; i < n_fds; i++) {
+                if (fds[i] < 0)
+                        continue;
+
+                if (opened)
+                        assert_se(fcntl(fds[i], F_GETFD) >= 0);
+                else
+                        assert_se(fcntl(fds[i], F_GETFD) < 0 && errno == EBADF);
+
+                c++;
+        }
+
+        return c; /* Return number of fds >= 0 in the array */
+}
+
+static void test_close_all_fds(void) {
+        _cleanup_free_ int *fds = NULL, *keep = NULL;
+        struct rlimit rl;
+        size_t n_fds, n_keep;
+
+        log_info("/* %s */", __func__);
+
+        rlimit_nofile_bump(-1);
+
+        assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
+        assert_se(rl.rlim_cur > 10);
+
+        /* Try to use 5000 fds, but when we can't bump the rlimit to make that happen use the whole limit minus 10 */
+        n_fds = MIN((rl.rlim_cur & ~1U) - 10U, 5000U);
+        assert_se((n_fds & 1U) == 0U); /* make sure even number of fds */
+
+        /* Allocate the determined number of fds, always two at a time */
+        assert_se(fds = new(int, n_fds));
+        for (size_t i = 0; i < n_fds; i += 2)
+                assert_se(pipe2(fds + i, O_CLOEXEC) >= 0);
+
+        /* Validate this worked */
+        assert_se(validate_fds(true, fds, n_fds) == n_fds);
+
+        /* Randomized number of fds to keep, but at most every second */
+        n_keep = (random_u64() % (n_fds / 2));
+
+        /* Now randomly select a number of fds from the array above to keep */
+        assert_se(keep = new(int, n_keep));
+        for (size_t k = 0; k < n_keep; k++) {
+                for (;;) {
+                        size_t p;
+
+                        p = random_u64() % n_fds;
+                        if (fds[p] >= 0) {
+                                keep[k] = TAKE_FD(fds[p]);
+                                break;
+                        }
+                }
+        }
+
+        /* Check that all fds from both arrays are still open, and test how many in each are >= 0 */
+        assert_se(validate_fds(true, fds, n_fds) == n_fds - n_keep);
+        assert_se(validate_fds(true, keep, n_keep) == n_keep);
+
+        /* Close logging fd first, so that we don't confuse it by closing its fd */
+        log_close();
+        log_set_open_when_needed(true);
+
+        /* Close all but the ones to keep */
+        assert_se(close_all_fds(keep, n_keep) >= 0);
+
+        assert_se(validate_fds(false, fds, n_fds) == n_fds - n_keep);
+        assert_se(validate_fds(true, keep, n_keep) == n_keep);
+
+        /* Close everything else too! */
+        assert_se(close_all_fds(NULL, 0) >= 0);
+
+        assert_se(validate_fds(false, fds, n_fds) == n_fds - n_keep);
+        assert_se(validate_fds(false, keep, n_keep) == n_keep);
+
+        log_set_open_when_needed(false);
+        log_open();
+}
+
 int main(int argc, char *argv[]) {
 
         test_setup_logging(LOG_DEBUG);
@@ -330,6 +425,7 @@ int main(int argc, char *argv[]) {
         test_rearrange_stdio();
         test_fd_duplicate_data_fd();
         test_read_nr_open();
+        test_close_all_fds();
 
         return 0;
 }
index 283cf157babb8a258ef5f1a7fde19a19d028745e..cf2e34dc9d37bf47117b945c12bae23a34803874 100644 (file)
@@ -12,6 +12,8 @@ static void test_issue_9549(void) {
         _cleanup_(table_unrefp) Table *table = NULL;
         _cleanup_free_ char *formatted = NULL;
 
+        log_info("/* %s */", __func__);
+
         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,
@@ -36,6 +38,8 @@ static void test_multiline(void) {
         _cleanup_(table_unrefp) Table *table = NULL;
         _cleanup_free_ char *formatted = NULL;
 
+        log_info("/* %s */", __func__);
+
         assert_se(table = table_new("foo", "bar"));
 
         assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(1), 100) >= 0);
@@ -148,6 +152,8 @@ static void test_strv(void) {
         _cleanup_(table_unrefp) Table *table = NULL;
         _cleanup_free_ char *formatted = NULL;
 
+        log_info("/* %s */", __func__);
+
         assert_se(table = table_new("foo", "bar"));
 
         assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(1), 100) >= 0);
@@ -256,8 +262,111 @@ static void test_strv(void) {
         formatted = mfree(formatted);
 }
 
-int main(int argc, char *argv[]) {
+static void test_strv_wrapped(void) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        _cleanup_free_ char *formatted = NULL;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(table = table_new("foo", "bar"));
+
+        assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(1), 100) >= 0);
+
+        assert_se(table_add_many(table,
+                                 TABLE_STRV_WRAPPED, STRV_MAKE("three", "different", "lines"),
+                                 TABLE_STRV_WRAPPED, STRV_MAKE("two", "lines")) >= 0);
+
+        table_set_cell_height_max(table, 1);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                         BAR\n"
+                        "three different lines two lines\n"));
+        formatted = mfree(formatted);
+
+        table_set_cell_height_max(table, 2);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                         BAR\n"
+                        "three different lines two lines\n"));
+        formatted = mfree(formatted);
+
+        table_set_cell_height_max(table, 3);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                         BAR\n"
+                        "three different lines two lines\n"));
+        formatted = mfree(formatted);
+
+        table_set_cell_height_max(table, (size_t) -1);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                         BAR\n"
+                        "three different lines two lines\n"));
+        formatted = mfree(formatted);
+
+        assert_se(table_add_many(table,
+                                 TABLE_STRING, "short",
+                                 TABLE_STRV_WRAPPED, STRV_MAKE("a", "pair")) >= 0);
+
+        assert_se(table_add_many(table,
+                                 TABLE_STRV_WRAPPED, STRV_MAKE("short2"),
+                                 TABLE_STRV_WRAPPED, STRV_MAKE("a", "eight", "line", "ćęłł",
+                                                               "___5___", "___6___", "___7___", "___8___")) >= 0);
+
+        table_set_cell_height_max(table, 1);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                             BAR\n"
+                        "three different…          two lines\n"
+                        "short                        a pair\n"
+                        "short2           a eight line ćęłł…\n"));
+        formatted = mfree(formatted);
+
+        table_set_cell_height_max(table, 2);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                           BAR\n"
+                        "three different         two lines\n"
+                        "lines                            \n"
+                        "short                      a pair\n"
+                        "short2          a eight line ćęłł\n"
+                        "                 ___5___ ___6___…\n"));
+        formatted = mfree(formatted);
+
+        table_set_cell_height_max(table, 3);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                           BAR\n"
+                        "three different         two lines\n"
+                        "lines                            \n"
+                        "short                      a pair\n"
+                        "short2          a eight line ćęłł\n"
+                        "                  ___5___ ___6___\n"
+                        "                  ___7___ ___8___\n"));
+        formatted = mfree(formatted);
 
+        table_set_cell_height_max(table, (size_t) -1);
+        assert_se(table_format(table, &formatted) >= 0);
+        fputs(formatted, stdout);
+        assert_se(streq(formatted,
+                        "FOO                           BAR\n"
+                        "three different         two lines\n"
+                        "lines                            \n"
+                        "short                      a pair\n"
+                        "short2          a eight line ćęłł\n"
+                        "                  ___5___ ___6___\n"
+                        "                  ___7___ ___8___\n"));
+        formatted = mfree(formatted);
+}
+
+int main(int argc, char *argv[]) {
         _cleanup_(table_unrefp) Table *t = NULL;
         _cleanup_free_ char *formatted = NULL;
 
@@ -399,6 +508,7 @@ int main(int argc, char *argv[]) {
         test_issue_9549();
         test_multiline();
         test_strv();
+        test_strv_wrapped();
 
         return 0;
 }
index 187be69d15e2cccfdaa003903161fff7af03a51e..f3506045a1f2634deb6e23179e363e43bbd464d4 100644 (file)
@@ -13,12 +13,11 @@ int fstab_filter_options(const char *opts, const char *names,
 */
 
 static void do_fstab_filter_options(const char *opts,
-                                      const char *remove,
-                                      int r_expected,
-                                      const char *name_expected,
-                                      const char *value_expected,
-                                      const char *filtered_expected) {
-
+                                    const char *remove,
+                                    int r_expected,
+                                    const char *name_expected,
+                                    const char *value_expected,
+                                    const char *filtered_expected) {
         int r;
         const char *name;
         _cleanup_free_ char *value = NULL, *filtered = NULL;
@@ -34,7 +33,7 @@ static void do_fstab_filter_options(const char *opts,
 
         /* also test the malloc-less mode */
         r = fstab_filter_options(opts, remove, &name, NULL, NULL);
-        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"",
+        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
                  opts, r, name,
                  r_expected, name_expected);
         assert_se(r == r_expected);
@@ -54,6 +53,12 @@ static void test_fstab_filter_options(void) {
         do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other");
         do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other");
 
+        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other");
+        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar");
+        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part");
+        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt");
+        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
+
         do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
         do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
         do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
index 4b658a0bdbbc70787ad154a5f6c0ba0ba2e06776..4565d656768b20119de65175acfc255fd83ca528 100644 (file)
@@ -1,11 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "clean-ipc.h"
-#include "user-util.h"
+#include "errno-util.h"
+#include "main-func.h"
 #include "tests.h"
-#include "util.h"
+#include "user-util.h"
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
         uid_t uid;
         int r;
         const char* name = argv[1] ?: NOBODY_USER_NAME;
@@ -15,11 +16,14 @@ int main(int argc, char *argv[]) {
         r = get_user_creds(&name, &uid, NULL, NULL, NULL, 0);
         if (r == -ESRCH)
                 return log_tests_skipped("Failed to resolve user");
-        if (r < 0) {
-                log_error_errno(r, "Failed to resolve \"%s\": %m", name);
-                return EXIT_FAILURE;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to resolve \"%s\": %m", name);
 
         r = clean_ipc_by_uid(uid);
-        return  r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        if (ERRNO_IS_PRIVILEGE(r))
+                return log_tests_skipped("No privileges");
+
+        return r;
 }
+
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
index 3ca8e1b10832f68d7d60c8b3430c15a6193d0331..2cc679f42e1abfd5a0cfc36c840ccdddddc1f846 100644 (file)
@@ -106,7 +106,7 @@ static void test_device_parents(struct udev *udev, const char *syspath) {
 
         log_info("/* %s, device %s */", __func__, syspath);
         device = udev_device_new_from_syspath(udev, syspath);
-        if (device == NULL)
+        if (!device)
                 return;
 
         log_info("looking at parents");
@@ -142,7 +142,7 @@ static void test_device_subsys_name(struct udev *udev, const char *subsys, const
 
         log_info("looking up device: '%s:%s'", subsys, dev);
         device = udev_device_new_from_subsystem_sysname(udev, subsys, dev);
-        if (device == NULL)
+        if (!device)
                 log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m");
         else
                 print_device(device);
@@ -213,7 +213,7 @@ static void test_monitor(struct udev *udev) {
                 for (i = 0; i < fdcount; i++) {
                         if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
                                 device = udev_monitor_receive_device(udev_monitor);
-                                if (device == NULL) {
+                                if (!device) {
                                         printf("no device from socket\n");
                                         continue;
                                 }
index 799ac6a51a263f2fd8f2fdd135cc1f0a427e0e39..bf74cbe6e1411029728b0a8f193507ae24db4d5b 100644 (file)
@@ -748,26 +748,26 @@ static void test_config_parse_pass_environ(void) {
         _cleanup_strv_free_ char **passenv = NULL;
 
         r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
-                              "PassEnvironment", 0, "A B",
-                              &passenv, NULL);
+                                      "PassEnvironment", 0, "A B",
+                                      &passenv, NULL);
         assert_se(r >= 0);
         assert_se(strv_length(passenv) == 2);
         assert_se(streq(passenv[0], "A"));
         assert_se(streq(passenv[1], "B"));
 
         r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
-                              "PassEnvironment", 0, "",
-                              &passenv, NULL);
+                                      "PassEnvironment", 0, "",
+                                      &passenv, NULL);
         assert_se(r >= 0);
         assert_se(strv_isempty(passenv));
 
         r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
-                              "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
-                              &passenv, NULL);
+                                      "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 'special_name$$' \\",
+                                      &passenv, NULL);
         assert_se(r >= 0);
-        assert_se(strv_length(passenv) == 1);
+        assert_se(strv_length(passenv) == 2);
         assert_se(streq(passenv[0], "normal_name"));
-
+        assert_se(streq(passenv[1], "special_name$$"));
 }
 
 static void test_unit_dump_config_items(void) {
index 30b00ae4d8b72c747442babf4e928d33b8b8f869..ada5b1712c6a5df5d937903f0d883d6ef3bbaef5 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sched.h>
 #include <sys/mount.h>
 #include <unistd.h>
 
@@ -258,6 +259,16 @@ static void test_path_is_mount_point(void) {
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
+        /* let's move into our own mount namespace with all propagation from the host turned off, so that
+         * /proc/self/mountinfo is static and constant for the whole time our test runs. */
+        if (unshare(CLONE_NEWNS) < 0) {
+                if (!ERRNO_IS_PRIVILEGE(errno))
+                        return log_error_errno(errno, "Failed to detach mount namespace: %m");
+
+                log_notice("Lacking privilege to create separate mount namespace, proceeding in originating mount namespace.");
+        } else
+                assert_se(mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL) >= 0);
+
         test_mount_propagation_flags("shared", 0, MS_SHARED);
         test_mount_propagation_flags("slave", 0, MS_SLAVE);
         test_mount_propagation_flags("private", 0, MS_PRIVATE);
index 397220732985fa89736181124509407cbe5e5609..7571e609a26fe8236a4c691881b00a9a6c91a9ca 100644 (file)
@@ -46,7 +46,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
                 c = strjoina(a, "/tmp");
                 assert_se(stat(c, &x) >= 0);
                 assert_se(S_ISDIR(x.st_mode));
-                assert_se((x.st_mode & 01777) == 01777);
+                assert_se(FLAGS_SET(x.st_mode, 01777));
                 assert_se(rmdir(c) >= 0);
                 assert_se(rmdir(a) >= 0);
         }
@@ -57,7 +57,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
                 d = strjoina(b, "/tmp");
                 assert_se(stat(d, &y) >= 0);
                 assert_se(S_ISDIR(y.st_mode));
-                assert_se((y.st_mode & 01777) == 01777);
+                assert_se(FLAGS_SET(y.st_mode, 01777));
                 assert_se(rmdir(d) >= 0);
                 assert_se(rmdir(b) >= 0);
         }
index 3806c3f8cf92db7f3490242b86b973e4325a8db5..d4f908f5d46875601965cb93ed2dd436f5181999 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <linux/loadavg.h>
 #include <locale.h>
 #include <math.h>
 #include <sys/socket.h>
@@ -929,6 +930,42 @@ static void test_parse_mtu(void) {
         assert_se(parse_mtu(AF_UNSPEC, "", &mtu) == -EINVAL);
 }
 
+static void test_parse_loadavg_fixed_point(void) {
+        loadavg_t fp;
+
+        assert_se(parse_loadavg_fixed_point("1.23", &fp) == 0);
+        assert_se(LOAD_INT(fp) == 1);
+        assert_se(LOAD_FRAC(fp) == 23);
+
+        assert_se(parse_loadavg_fixed_point("1.80", &fp) == 0);
+        assert_se(LOAD_INT(fp) == 1);
+        assert_se(LOAD_FRAC(fp) == 80);
+
+        assert_se(parse_loadavg_fixed_point("0.07", &fp) == 0);
+        assert_se(LOAD_INT(fp) == 0);
+        assert_se(LOAD_FRAC(fp) == 7);
+
+        assert_se(parse_loadavg_fixed_point("0.00", &fp) == 0);
+        assert_se(LOAD_INT(fp) == 0);
+        assert_se(LOAD_FRAC(fp) == 0);
+
+        assert_se(parse_loadavg_fixed_point("4096.57", &fp) == 0);
+        assert_se(LOAD_INT(fp) == 4096);
+        assert_se(LOAD_FRAC(fp) == 57);
+
+        /* Caps out at 2 digit fracs */
+        assert_se(parse_loadavg_fixed_point("1.100", &fp) == -ERANGE);
+
+        assert_se(parse_loadavg_fixed_point("4096.4096", &fp) == -ERANGE);
+        assert_se(parse_loadavg_fixed_point("-4000.5", &fp) == -ERANGE);
+        assert_se(parse_loadavg_fixed_point("18446744073709551615.5", &fp) == -ERANGE);
+        assert_se(parse_loadavg_fixed_point("foobar", &fp) == -EINVAL);
+        assert_se(parse_loadavg_fixed_point("3333", &fp) == -EINVAL);
+        assert_se(parse_loadavg_fixed_point("1.2.3", &fp) == -EINVAL);
+        assert_se(parse_loadavg_fixed_point(".", &fp) == -EINVAL);
+        assert_se(parse_loadavg_fixed_point("", &fp) == -EINVAL);
+}
+
 int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
@@ -955,6 +992,7 @@ int main(int argc, char *argv[]) {
         test_parse_errno();
         test_parse_syscall_and_errno();
         test_parse_mtu();
+        test_parse_loadavg_fixed_point();
 
         return 0;
 }
index cf89d89482fdcf8db05c7028b3ed779d7303bdab..2e20674c2f39ebaca5489d7950266d2c9e18e9c4 100644 (file)
@@ -1,7 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <stdbool.h>
-#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -78,32 +77,52 @@ static Service *service_for_path(Manager *m, Path *path, const char *service_nam
         return SERVICE(service_unit);
 }
 
-static void check_states(Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) {
+static int _check_states(unsigned line,
+                         Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) {
         assert_se(m);
         assert_se(service);
 
         usec_t end = now(CLOCK_MONOTONIC) + 30 * USEC_PER_SEC;
 
-        while (path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS ||
-               path->state != path_state || service->state != service_state) {
+        while (path->state != path_state || service->state != service_state ||
+               path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS) {
 
                 assert_se(sd_event_run(m->event, 100 * USEC_PER_MSEC) >= 0);
 
-                printf("%s: state = %s; result = %s \n",
-                                UNIT(path)->id,
-                                path_state_to_string(path->state),
-                                path_result_to_string(path->result));
-                printf("%s: state = %s; result = %s \n",
-                                UNIT(service)->id,
-                                service_state_to_string(service->state),
-                                service_result_to_string(service->result));
-
-                if (now(CLOCK_MONOTONIC) >= end) {
+                usec_t n = now(CLOCK_MONOTONIC);
+                log_info("line %u: %s: state = %s; result = %s (left: %" PRIi64 ")",
+                         line,
+                         UNIT(path)->id,
+                         path_state_to_string(path->state),
+                         path_result_to_string(path->result),
+                         end - n);
+                log_info("line %u: %s: state = %s; result = %s",
+                         line,
+                         UNIT(service)->id,
+                         service_state_to_string(service->state),
+                         service_result_to_string(service->result));
+
+                if (service->state == SERVICE_FAILED &&
+                    service->main_exec_status.status == EXIT_CGROUP &&
+                    !ci_environment())
+                        /* On a general purpose system we may fail to start the service for reasons which are
+                         * not under our control: permission limits, resource exhaustion, etc. Let's skip the
+                         * test in those cases. On developer machines we require proper setup. */
+                        return log_notice_errno(SYNTHETIC_ERRNO(ECANCELED),
+                                                "Failed to start service %s, aborting test: %s/%s",
+                                                UNIT(service)->id,
+                                                service_state_to_string(service->state),
+                                                service_result_to_string(service->result));
+
+                if (n >= end) {
                         log_error("Test timeout when testing %s", UNIT(path)->id);
                         exit(EXIT_FAILURE);
                 }
         }
+
+        return 0;
 }
+#define check_states(...) _check_states(__LINE__, __VA_ARGS__)
 
 static void test_path_exists(Manager *m) {
         const char *test_path = "/tmp/test-path_exists";
@@ -119,18 +138,22 @@ static void test_path_exists(Manager *m) {
         service = service_for_path(m, path, NULL);
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(touch(test_path) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         /* Service restarts if file still exists */
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(unit_stop(unit) >= 0);
 }
@@ -149,18 +172,22 @@ static void test_path_existsglob(Manager *m) {
         service = service_for_path(m, path, NULL);
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(touch(test_path) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         /* Service restarts if file still exists */
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(unit_stop(unit) >= 0);
 }
@@ -180,23 +207,28 @@ static void test_path_changed(Manager *m) {
         service = service_for_path(m, path, NULL);
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(touch(test_path) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         /* Service does not restart if file still exists */
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         f = fopen(test_path, "w");
         assert_se(f);
         fclose(f);
 
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
         assert_se(unit_stop(unit) >= 0);
@@ -217,23 +249,28 @@ static void test_path_modified(Manager *m) {
         service = service_for_path(m, path, NULL);
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(touch(test_path) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         /* Service does not restart if file still exists */
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         f = fopen(test_path, "w");
         assert_se(f);
         fputs("test", f);
 
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
         assert_se(unit_stop(unit) >= 0);
@@ -253,14 +290,17 @@ static void test_path_unit(Manager *m) {
         service = service_for_path(m, path, "path-mycustomunit.service");
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(touch(test_path) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(unit_stop(unit) >= 0);
 }
@@ -281,22 +321,26 @@ static void test_path_directorynotempty(Manager *m) {
         assert_se(access(test_path, F_OK) < 0);
 
         assert_se(unit_start(unit) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         /* MakeDirectory default to no */
         assert_se(access(test_path, F_OK) < 0);
 
         assert_se(mkdir_p(test_path, 0755) >= 0);
         assert_se(touch(strjoina(test_path, "test_file")) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         /* Service restarts if directory is still not empty */
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
+        if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
+                return;
 
         assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
         assert_se(unit_stop(UNIT(service)) >= 0);
-        check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
+        if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
+                return;
 
         assert_se(unit_stop(unit) >= 0);
 }
diff --git a/src/test/test-psi-util.c b/src/test/test-psi-util.c
new file mode 100644 (file)
index 0000000..bde8ef8
--- /dev/null
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/loadavg.h>
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "psi-util.h"
+#include "tests.h"
+
+static void test_read_mem_pressure(void) {
+        _cleanup_(unlink_tempfilep) char path[] = "/tmp/pressurereadtestXXXXXX";
+        ResourcePressure rp;
+
+        if (geteuid() != 0)
+                return (void) log_tests_skipped("not root");
+
+        assert_se(mkstemp(path));
+
+        assert_se(read_resource_pressure("/verylikelynonexistentpath", PRESSURE_TYPE_SOME, &rp) < 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) < 0);
+
+        assert_se(write_string_file(path, "herpdederp\n", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) < 0);
+
+        /* Pressure file with some invalid values*/
+        assert_se(write_string_file(path, "some avg10=0.22=55 avg60=0.17=8 avg300=1.11=00 total=58761459\n"
+                                          "full avg10=0.23=55 avg60=0.16=8 avg300=1.08=00 total=58464525", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) < 0);
+
+        /* Same pressure valid values as below but with duplicate avg60 field */
+        assert_se(write_string_file(path, "some avg10=0.22 avg60=0.17 avg60=0.18 avg300=1.11 total=58761459\n"
+                                          "full avg10=0.23 avg60=0.16 avg300=1.08 total=58464525", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) < 0);
+
+        assert_se(write_string_file(path, "some avg10=0.22 avg60=0.17 avg300=1.11 total=58761459\n"
+                                          "full avg10=0.23 avg60=0.16 avg300=1.08 total=58464525", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) == 0);
+        assert_se(LOAD_INT(rp.avg10) == 0);
+        assert_se(LOAD_FRAC(rp.avg10) == 22);
+        assert_se(LOAD_INT(rp.avg60) == 0);
+        assert_se(LOAD_FRAC(rp.avg60) == 17);
+        assert_se(LOAD_INT(rp.avg300) == 1);
+        assert_se(LOAD_FRAC(rp.avg300) == 11);
+        assert_se(rp.total == 58761459);
+        assert(read_resource_pressure(path, PRESSURE_TYPE_FULL, &rp) == 0);
+        assert_se(LOAD_INT(rp.avg10) == 0);
+        assert_se(LOAD_FRAC(rp.avg10) == 23);
+        assert_se(LOAD_INT(rp.avg60) == 0);
+        assert_se(LOAD_FRAC(rp.avg60) == 16);
+        assert_se(LOAD_INT(rp.avg300) == 1);
+        assert_se(LOAD_FRAC(rp.avg300) == 8);
+        assert_se(rp.total == 58464525);
+
+        /* Pressure file with extra unsupported fields */
+        assert_se(write_string_file(path, "some avg5=0.55 avg10=0.22 avg60=0.17 avg300=1.11 total=58761459\n"
+                                          "full avg10=0.23 avg60=0.16 avg300=1.08 avg600=2.00 total=58464525", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) == 0);
+        assert_se(LOAD_INT(rp.avg10) == 0);
+        assert_se(LOAD_FRAC(rp.avg10) == 22);
+        assert_se(LOAD_INT(rp.avg60) == 0);
+        assert_se(LOAD_FRAC(rp.avg60) == 17);
+        assert_se(LOAD_INT(rp.avg300) == 1);
+        assert_se(LOAD_FRAC(rp.avg300) == 11);
+        assert_se(rp.total == 58761459);
+        assert(read_resource_pressure(path, PRESSURE_TYPE_FULL, &rp) == 0);
+        assert_se(LOAD_INT(rp.avg10) == 0);
+        assert_se(LOAD_FRAC(rp.avg10) == 23);
+        assert_se(LOAD_INT(rp.avg60) == 0);
+        assert_se(LOAD_FRAC(rp.avg60) == 16);
+        assert_se(LOAD_INT(rp.avg300) == 1);
+        assert_se(LOAD_FRAC(rp.avg300) == 8);
+        assert_se(rp.total == 58464525);
+}
+
+int main(void) {
+        test_setup_logging(LOG_DEBUG);
+        test_read_mem_pressure();
+        return 0;
+}
index 558ffeef511513c38e2789963e76522a9bf6fc54..f681795ebe656dd681495480d49d4f23a7009beb 100644 (file)
@@ -162,71 +162,84 @@ static void test_strv_find_startswith(void) {
 }
 
 static void test_strv_join(void) {
-        _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
-
         log_info("/* %s */", __func__);
 
-        p = strv_join((char **)input_table_multiple, ", ");
+        _cleanup_free_ char *p = strv_join((char **)input_table_multiple, ", ");
         assert_se(p);
         assert_se(streq(p, "one, two, three"));
 
-        q = strv_join((char **)input_table_multiple, ";");
+        _cleanup_free_ char *q = strv_join((char **)input_table_multiple, ";");
         assert_se(q);
         assert_se(streq(q, "one;two;three"));
 
-        r = strv_join((char **)input_table_multiple, NULL);
+        _cleanup_free_ char *r = strv_join((char **)input_table_multiple, NULL);
         assert_se(r);
         assert_se(streq(r, "one two three"));
 
-        s = strv_join((char **)input_table_one, ", ");
+        _cleanup_free_ char *s = strv_join(STRV_MAKE("1", "2", "3,3"), ",");
         assert_se(s);
-        assert_se(streq(s, "one"));
+        assert_se(streq(s, "1,2,3,3"));
 
-        t = strv_join((char **)input_table_none, ", ");
+        _cleanup_free_ char *t = strv_join((char **)input_table_one, ", ");
         assert_se(t);
-        assert_se(streq(t, ""));
+        assert_se(streq(t, "one"));
+
+        _cleanup_free_ char *u = strv_join((char **)input_table_none, ", ");
+        assert_se(u);
+        assert_se(streq(u, ""));
 
-        v = strv_join((char **)input_table_two_empties, ", ");
+        _cleanup_free_ char *v = strv_join((char **)input_table_two_empties, ", ");
         assert_se(v);
         assert_se(streq(v, ", "));
 
-        w = strv_join((char **)input_table_one_empty, ", ");
+        _cleanup_free_ char *w = strv_join((char **)input_table_one_empty, ", ");
         assert_se(w);
         assert_se(streq(w, ""));
 }
 
-static void test_strv_join_prefix(void) {
-        _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
-
+static void test_strv_join_full(void) {
         log_info("/* %s */", __func__);
 
-        p = strv_join_prefix((char **)input_table_multiple, ", ", "foo");
+        _cleanup_free_ char *p = strv_join_full((char **)input_table_multiple, ", ", "foo", false);
         assert_se(p);
         assert_se(streq(p, "fooone, footwo, foothree"));
 
-        q = strv_join_prefix((char **)input_table_multiple, ";", "foo");
+        _cleanup_free_ char *q = strv_join_full((char **)input_table_multiple, ";", "foo", false);
         assert_se(q);
         assert_se(streq(q, "fooone;footwo;foothree"));
 
-        r = strv_join_prefix((char **)input_table_multiple, NULL, "foo");
+        _cleanup_free_ char *r = strv_join_full(STRV_MAKE("a", "a;b", "a:c"), ";", NULL, true);
         assert_se(r);
-        assert_se(streq(r, "fooone footwo foothree"));
+        assert_se(streq(r, "a;a\\;b;a:c"));
 
-        s = strv_join_prefix((char **)input_table_one, ", ", "foo");
+        _cleanup_free_ char *s = strv_join_full(STRV_MAKE("a", "a;b", "a;;c", ";", ";x"), ";", NULL, true);
         assert_se(s);
-        assert_se(streq(s, "fooone"));
+        assert_se(streq(s, "a;a\\;b;a\\;\\;c;\\;;\\;x"));
 
-        t = strv_join_prefix((char **)input_table_none, ", ", "foo");
+        _cleanup_free_ char *t = strv_join_full(STRV_MAKE("a", "a;b", "a:c", ";"), ";", "=", true);
         assert_se(t);
-        assert_se(streq(t, ""));
+        assert_se(streq(t, "=a;=a\\;b;=a:c;=\\;"));
+        t = mfree(t);
+
+        _cleanup_free_ char *u = strv_join_full((char **)input_table_multiple, NULL, "foo", false);
+        assert_se(u);
+        assert_se(streq(u, "fooone footwo foothree"));
 
-        v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo");
+        _cleanup_free_ char *v = strv_join_full((char **)input_table_one, ", ", "foo", false);
         assert_se(v);
-        assert_se(streq(v, "foo, foo"));
+        assert_se(streq(v, "fooone"));
 
-        w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo");
+        _cleanup_free_ char *w = strv_join_full((char **)input_table_none, ", ", "foo", false);
         assert_se(w);
-        assert_se(streq(w, "foo"));
+        assert_se(streq(w, ""));
+
+        _cleanup_free_ char *x = strv_join_full((char **)input_table_two_empties, ", ", "foo", false);
+        assert_se(x);
+        assert_se(streq(x, "foo, foo"));
+
+        _cleanup_free_ char *y = strv_join_full((char **)input_table_one_empty, ", ", "foo", false);
+        assert_se(y);
+        assert_se(streq(y, "foo"));
 }
 
 static void test_strv_unquote(const char *quoted, char **list) {
@@ -995,7 +1008,7 @@ int main(int argc, char *argv[]) {
         test_strv_find_prefix();
         test_strv_find_startswith();
         test_strv_join();
-        test_strv_join_prefix();
+        test_strv_join_full();
 
         test_strv_unquote("    foo=bar     \"waldo\"    zzz    ", STRV_MAKE("foo=bar", "waldo", "zzz"));
         test_strv_unquote("", STRV_MAKE_EMPTY);
index 59f90b76ec4ac71ded12201008a1a64e7018b7d7..72736111438555232237e2e48cea3c03f48a2f65 100644 (file)
@@ -3,6 +3,7 @@
 #include "architecture.h"
 #include "automount.h"
 #include "cgroup.h"
+#include "cgroup-util.h"
 #include "compress.h"
 #include "condition.h"
 #include "device-private.h"
@@ -71,6 +72,7 @@ int main(int argc, char **argv) {
         test_table(locale_variable, VARIABLE_LC);
         test_table(log_target, LOG_TARGET);
         test_table(mac_address_policy, MAC_ADDRESS_POLICY);
+        test_table(managed_oom_mode, MANAGED_OOM_MODE);
         test_table(manager_state, MANAGER_STATE);
         test_table(manager_timestamp, MANAGER_TIMESTAMP);
         test_table(mount_exec_command, MOUNT_EXEC_COMMAND);
diff --git a/src/test/test-user-record.c b/src/test/test-user-record.c
new file mode 100644 (file)
index 0000000..d623706
--- /dev/null
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "fd-util.h"
+#include "fileio.h"
+#include "format-util.h"
+#include "fs-util.h"
+#include "tmpfile-util.h"
+#include "tests.h"
+#include "user-record.h"
+
+static void test_read_login_defs(const char *path) {
+        log_info("/* %s(\"%s\") */", __func__, path ?: "<custom>");
+
+        _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-user-record.XXXXXX";
+        _cleanup_fclose_ FILE *f = NULL;
+        if (!path) {
+                assert_se(fmkostemp_safe(name, "r+", &f) == 0);
+                fprintf(f,
+                        "SYS_UID_MIN "UID_FMT"\n"
+                        "SYS_UID_MAX "UID_FMT"\n"
+                        "SYS_GID_MIN "GID_FMT"\n"
+                        "SYS_GID_MAX "GID_FMT"\n",
+                        SYSTEM_ALLOC_UID_MIN + 5,
+                        SYSTEM_UID_MAX + 5,
+                        SYSTEM_ALLOC_GID_MIN + 5,
+                        SYSTEM_GID_MAX + 5);
+                assert_se(fflush_and_check(f) >= 0);
+        }
+
+        UGIDAllocationRange defs;
+        assert_se(read_login_defs(&defs, path ?: name, NULL) >= 0);
+
+        log_info("system_alloc_uid_min="UID_FMT, defs.system_alloc_uid_min);
+        log_info("system_uid_max="UID_FMT, defs.system_uid_max);
+        log_info("system_alloc_gid_min="GID_FMT, defs.system_alloc_gid_min);
+        log_info("system_gid_max="GID_FMT, defs.system_gid_max);
+
+        if (!path) {
+                uid_t offset = ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES ? 5 : 0;
+                assert_se(defs.system_alloc_uid_min == SYSTEM_ALLOC_UID_MIN + offset);
+                assert_se(defs.system_uid_max == SYSTEM_UID_MAX + offset);
+                assert_se(defs.system_alloc_gid_min == SYSTEM_ALLOC_GID_MIN + offset);
+                assert_se(defs.system_gid_max == SYSTEM_GID_MAX + offset);
+        } else if (streq(path, "/dev/null")) {
+                assert_se(defs.system_alloc_uid_min == SYSTEM_ALLOC_UID_MIN);
+                assert_se(defs.system_uid_max == SYSTEM_UID_MAX);
+                assert_se(defs.system_alloc_gid_min == SYSTEM_ALLOC_GID_MIN);
+                assert_se(defs.system_gid_max == SYSTEM_GID_MAX);
+        }
+}
+
+static void test_acquire_ugid_allocation_range(void) {
+        log_info("/* %s */", __func__);
+
+        const UGIDAllocationRange *defs;
+        assert_se(defs = acquire_ugid_allocation_range());
+
+        log_info("system_alloc_uid_min="UID_FMT, defs->system_alloc_uid_min);
+        log_info("system_uid_max="UID_FMT, defs->system_uid_max);
+        log_info("system_alloc_gid_min="GID_FMT, defs->system_alloc_gid_min);
+        log_info("system_gid_max="GID_FMT, defs->system_gid_max);
+}
+
+static void test_uid_is_system(void) {
+        log_info("/* %s */", __func__);
+
+        uid_t uid = 0;
+        log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
+
+        uid = 999;
+        log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
+
+        uid = getuid();
+        log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
+}
+
+static void test_gid_is_system(void) {
+        log_info("/* %s */", __func__);
+
+        gid_t gid = 0;
+        log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
+
+        gid = 999;
+        log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
+
+        gid = getgid();
+        log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_DEBUG);
+
+        test_read_login_defs("/dev/null");
+        test_read_login_defs("/etc/login.defs");
+        test_read_login_defs(NULL);
+        test_acquire_ugid_allocation_range();
+        test_uid_is_system();
+        test_gid_is_system();
+
+        return 0;
+}
index d4a6c8f5c339029c3349c3dce31213307668dd9c..cfbafcc5ca630d1bf4ca665731639543d247d066 100644 (file)
@@ -414,6 +414,8 @@ static void test_foreach_pointer(void) {
         int a, b, c, *i;
         size_t k = 0;
 
+        log_info("/* %s */", __func__);
+
         FOREACH_POINTER(i, &a, &b, &c) {
                 switch (k) {
 
@@ -489,6 +491,17 @@ static void test_foreach_pointer(void) {
         assert(k == 11);
 }
 
+static void test_ptr_to_int(void) {
+        log_info("/* %s */", __func__);
+
+        /* Primary reason to have this test is to validate that pointers are large enough to hold entire int range */
+        assert_se(PTR_TO_INT(INT_TO_PTR(0)) == 0);
+        assert_se(PTR_TO_INT(INT_TO_PTR(1)) == 1);
+        assert_se(PTR_TO_INT(INT_TO_PTR(-1)) == -1);
+        assert_se(PTR_TO_INT(INT_TO_PTR(INT_MAX)) == INT_MAX);
+        assert_se(PTR_TO_INT(INT_TO_PTR(INT_MIN)) == INT_MIN);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_INFO);
 
@@ -508,6 +521,7 @@ int main(int argc, char *argv[]) {
         test_system_tasks_max();
         test_system_tasks_max_scale();
         test_foreach_pointer();
+        test_ptr_to_int();
 
         return 0;
 }
index b9b37008b128a5a56b966555c04afe3741a1d388..b6596fd0c731168935e5c599193ff18c89c3e0f6 100644 (file)
@@ -1063,7 +1063,7 @@ static int parse_acls_from_arg(Item *item) {
         if (r < 0)
                 log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument);
 #else
-        log_warning_errno(SYNTHETIC_ERRNO(ENOSYS), "ACLs are not supported. Ignoring");
+        log_warning("ACLs are not supported. Ignoring.");
 #endif
 
         return 0;
@@ -1417,10 +1417,10 @@ static int create_file(Item *i, const char *path) {
                 if (fstat(fd, &stbuf) < 0)
                         return log_error_errno(errno, "stat(%s) failed: %m", path);
 
-                if (!S_ISREG(stbuf.st_mode)) {
-                        log_error("%s exists and is not a regular file.", path);
-                        return -EEXIST;
-                }
+                if (!S_ISREG(stbuf.st_mode))
+                        return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                               "%s exists and is not a regular file.",
+                                               path);
 
                 st = &stbuf;
         } else {
@@ -1481,10 +1481,10 @@ static int truncate_file(Item *i, const char *path) {
 
                 fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode);
                 if (fd < 0) {
-                        if (errno == ENOENT) {
-                                log_error("Cannot create file %s on a read-only file system.", path);
-                                return -EROFS;
-                        }
+                        if (errno == ENOENT)
+                                return log_error_errno(SYNTHETIC_ERRNO(EROFS),
+                                                       "Cannot create file %s on a read-only file system.",
+                                                       path);
 
                         return log_error_errno(errno, "Failed to re-open file %s: %m", path);
                 }
@@ -1495,10 +1495,10 @@ static int truncate_file(Item *i, const char *path) {
         if (fstat(fd, &stbuf) < 0)
                 return log_error_errno(errno, "stat(%s) failed: %m", path);
 
-        if (!S_ISREG(stbuf.st_mode)) {
-                log_error("%s exists and is not a regular file.", path);
-                return -EEXIST;
-        }
+        if (!S_ISREG(stbuf.st_mode))
+                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                       "%s exists and is not a regular file.",
+                                       path);
 
         if (stbuf.st_size > 0) {
                 if (ftruncate(fd, 0) < 0) {
@@ -3105,11 +3105,15 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_IMAGE:
+#ifdef STANDALONE
+                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                               "This systemd-tmpfiles version is compiled without support for --image=.");
+#else
                         r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image);
                         if (r < 0)
                                 return r;
-
-                        /* Imply -E here since it makes little sense to create files persistently in the /run mointpoint of a disk image */
+#endif
+                        /* Imply -E here since it makes little sense to create files persistently in the /run mountpoint of a disk image */
                         _fallthrough_;
 
                 case 'E':
@@ -3331,9 +3335,11 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_
                                               ItemArray, item_array_free);
 
 static int run(int argc, char *argv[]) {
+#ifndef STANDALONE
         _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
         _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+#endif
         _cleanup_strv_free_ char **config_dirs = NULL;
         bool invalid_config = false;
         ItemArray *a;
@@ -3393,6 +3399,7 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
+#ifndef STANDALONE
         if (arg_image) {
                 assert(!arg_root);
 
@@ -3409,6 +3416,9 @@ static int run(int argc, char *argv[]) {
                 if (!arg_root)
                         return log_oom();
         }
+#else
+        assert(!arg_image);
+#endif
 
         items = ordered_hashmap_new(&item_array_hash_ops);
         globs = ordered_hashmap_new(&item_array_hash_ops);
index 03fd429b275287afbf4139d55fb192aae0204ac1..c23c2bdd2057624f4ed66d6b5f63d02ee6983552 100644 (file)
@@ -11,6 +11,7 @@
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "device-private.h"
 #include "device-util.h"
 #include "ethtool-util.h"
 #include "fd-util.h"
@@ -241,6 +242,7 @@ bool link_config_should_reload(link_config_ctx *ctx) {
 }
 
 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
+        unsigned name_assign_type = NET_NAME_UNKNOWN;
         struct ether_addr permanent_mac = {};
         unsigned short iftype = 0;
         link_config *link;
@@ -267,38 +269,89 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
         if (r < 0)
                 log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
 
+        (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
+
         LIST_FOREACH(links, link, ctx->links) {
                 if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
                                      link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
                                      device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
-                        if (link->match_name && !strv_contains(link->match_name, "*")) {
-                                unsigned name_assign_type = NET_NAME_UNKNOWN;
 
-                                (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
+                        if (link->match_name && !strv_contains(link->match_name, "*") && name_assign_type == NET_NAME_ENUM)
+                                log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.",
+                                                   link->filename);
+                        else
+                                log_device_debug(device, "Config file %s is applied", link->filename);
 
-                                if (name_assign_type == NET_NAME_ENUM) {
-                                        log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
-                                                           link->filename);
-                                        *ret = link;
+                        *ret = link;
+                        return 0;
+                }
+        }
 
-                                        return 0;
-                                } else if (name_assign_type == NET_NAME_RENAMED) {
-                                        log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
-                                                           link->filename);
+        return -ENOENT;
+}
 
-                                        continue;
-                                }
-                        }
+static int link_config_apply_ethtool_settings(int *ethtool_fd, const link_config *config, sd_device *device) {
+        const char *name;
+        int r;
 
-                        log_device_debug(device, "Config file %s is applied", link->filename);
+        assert(ethtool_fd);
+        assert(config);
+        assert(device);
 
-                        *ret = link;
-                        return 0;
+        r = sd_device_get_sysname(device, &name);
+        if (r < 0)
+                return log_device_error_errno(device, r, "Failed to get sysname: %m");
+
+        r = ethtool_set_glinksettings(ethtool_fd, name,
+                                      config->autonegotiation, config->advertise,
+                                      config->speed, config->duplex, config->port);
+        if (r < 0) {
+                if (config->port != _NET_DEV_PORT_INVALID)
+                        log_device_warning_errno(device, r, "Could not set port '%s', ignoring: %m", port_to_string(config->port));
+
+                if (!eqzero(config->advertise))
+                        log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); /* TODO: include modes in the log message. */
+
+                if (config->speed) {
+                        unsigned speed = DIV_ROUND_UP(config->speed, 1000000);
+                        if (r == -EOPNOTSUPP) {
+                                r = ethtool_set_speed(ethtool_fd, name, speed, config->duplex);
+                                if (r < 0)
+                                        log_device_warning_errno(device, r, "Could not set speed to %uMbps, ignoring: %m", speed);
+                        }
                 }
+
+                if (config->duplex != _DUP_INVALID)
+                        log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", duplex_to_string(config->duplex));
         }
 
-        *ret = NULL;
-        return -ENOENT;
+        r = ethtool_set_wol(ethtool_fd, name, config->wol);
+        if (r < 0)
+                log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", wol_to_string(config->wol));
+
+        r = ethtool_set_features(ethtool_fd, name, config->features);
+        if (r < 0)
+                log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m");
+
+        if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
+                r = ethtool_set_channels(ethtool_fd, name, &config->channels);
+                if (r < 0)
+                        log_device_warning_errno(device, r, "Could not set channels, ignoring: %m");
+        }
+
+        if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
+                r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
+                if (r < 0)
+                        log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m");
+        }
+
+        if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
+                r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
+                if (r < 0)
+                        log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
+        }
+
+        return 0;
 }
 
 static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
@@ -357,80 +410,41 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr
         return 1;
 }
 
-int link_config_apply(link_config_ctx *ctx, link_config *config,
-                      sd_device *device, const char **name) {
-        _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
-        struct ether_addr generated_mac;
-        struct ether_addr *mac = NULL;
-        const char *new_name = NULL;
-        const char *old_name;
-        unsigned speed, name_type = NET_NAME_UNKNOWN;
-        NamePolicy policy;
-        int r, ifindex;
+static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config *config, sd_device *device) {
+        struct ether_addr generated_mac, *mac = NULL;
+        int ifindex, r;
 
-        assert(ctx);
+        assert(rtnl);
         assert(config);
         assert(device);
-        assert(name);
 
-        r = sd_device_get_sysname(device, &old_name);
+        r = sd_device_get_ifindex(device, &ifindex);
         if (r < 0)
-                return r;
+                return log_device_error_errno(device, r, "Could not find ifindex: %m");
 
-        r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
-                                      config->autonegotiation, config->advertise,
-                                      config->speed, config->duplex, config->port);
-        if (r < 0) {
-
-                if (config->port != _NET_DEV_PORT_INVALID)
-                        log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
-
-                if (!eqzero(config->advertise))
-                        log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
-
-                if (config->speed) {
-                        speed = DIV_ROUND_UP(config->speed, 1000000);
-                        if (r == -EOPNOTSUPP) {
-                                r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
-                                if (r < 0)
-                                        log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
-                        }
-                }
-
-                if (config->duplex != _DUP_INVALID)
-                        log_warning_errno(r, "Could not set duplex of %s to %s: %m", old_name, duplex_to_string(config->duplex));
-        }
-
-        r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
-        if (r < 0)
-                log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
-                                  old_name, wol_to_string(config->wol));
+        if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
+                if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
+                        mac = &generated_mac;
+        } else
+                mac = config->mac;
 
-        r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
+        r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu);
         if (r < 0)
-                log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
-
-        if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
-                r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
-                if (r < 0)
-                        log_warning_errno(r, "Could not set channels of %s: %m", old_name);
-        }
+                log_device_warning_errno(device, r, "Could not set Alias=, MACAddress= or MTU=, ignoring: %m");
 
-        if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
-                r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
-                if (r < 0)
-                        log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
-        }
+        return 0;
+}
 
-        if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
-                r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
-                if (r < 0)
-                        log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
-        }
+static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
+        unsigned name_type = NET_NAME_UNKNOWN;
+        const char *new_name = NULL;
+        NamePolicy policy;
+        int r;
 
-        r = sd_device_get_ifindex(device, &ifindex);
-        if (r < 0)
-                return log_device_warning_errno(device, r, "Could not find ifindex: %m");
+        assert(ctx);
+        assert(config);
+        assert(device);
+        assert(ret_name);
 
         (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
 
@@ -482,24 +496,43 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                                 break;
                 }
 
-        if (new_name)
+        if (new_name) {
                 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
-        else if (config->name) {
-                new_name = config->name;
-                log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
-        } else
-                log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
- no_rename:
+                *ret_name = new_name;
+                return 0;
+        }
 
-        if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
-                if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
-                        mac = &generated_mac;
-        } else
-                mac = config->mac;
+        if (config->name) {
+                log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name);
+                *ret_name = config->name;
+                return 0;
+        }
+
+        log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
+no_rename:
+        r = sd_device_get_sysname(device, ret_name);
+        if (r < 0)
+                return log_device_error_errno(device, r, "Failed to get sysname: %m");
+
+        return 0;
+}
+
+static int link_config_apply_alternative_names(sd_netlink **rtnl, const link_config *config, sd_device *device, const char *new_name) {
+        _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
+        const char *current_name;
+        int ifindex, r;
+
+        assert(rtnl);
+        assert(config);
+        assert(device);
+
+        r = sd_device_get_sysname(device, &current_name);
+        if (r < 0)
+                return log_device_error_errno(device, r, "Failed to get sysname: %m");
 
-        r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
+        r = sd_device_get_ifindex(device, &ifindex);
         if (r < 0)
-                return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
+                return log_device_error_errno(device, r, "Could not find ifindex: %m");
 
         if (config->alternative_names) {
                 altnames = strv_copy(config->alternative_names);
@@ -539,11 +572,11 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
 
         if (new_name)
                 strv_remove(altnames, new_name);
-        strv_remove(altnames, old_name);
+        strv_remove(altnames, current_name);
 
-        r = rtnl_get_link_alternative_names(&ctx->rtnl, ifindex, &current_altnames);
+        r = rtnl_get_link_alternative_names(rtnl, ifindex, &current_altnames);
         if (r < 0)
-                log_debug_errno(r, "Failed to get alternative names on %s, ignoring: %m", old_name);
+                log_device_debug_errno(device, r, "Failed to get alternative names, ignoring: %m");
 
         char **p;
         STRV_FOREACH(p, current_altnames)
@@ -551,14 +584,63 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
 
         strv_uniq(altnames);
         strv_sort(altnames);
-        r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, altnames);
-        if (r == -EOPNOTSUPP)
-                log_debug_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s, ignoring: %m", old_name);
-        else if (r < 0)
-                return log_warning_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s: %m", old_name);
+        r = rtnl_set_link_alternative_names(rtnl, ifindex, altnames);
+        if (r < 0)
+                log_device_full_errno(device, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
+                                      "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
+
+        return 0;
+}
+
+int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
+        const char *new_name;
+        DeviceAction a;
+        int r;
+
+        assert(ctx);
+        assert(config);
+        assert(device);
+        assert(ret_name);
+
+        r = device_get_action(device, &a);
+        if (r < 0)
+                return log_device_error_errno(device, r, "Failed to get ACTION= property: %m");
+
+        if (!IN_SET(a, DEVICE_ACTION_ADD, DEVICE_ACTION_BIND, DEVICE_ACTION_MOVE)) {
+                log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a));
 
-        *name = new_name;
+                r = sd_device_get_sysname(device, ret_name);
+                if (r < 0)
+                        return log_device_error_errno(device, r, "Failed to get sysname: %m");
+
+                return 0;
+        }
+
+        r = link_config_apply_ethtool_settings(&ctx->ethtool_fd, config, device);
+        if (r < 0)
+                return r;
+
+        r = link_config_apply_rtnl_settings(&ctx->rtnl, config, device);
+        if (r < 0)
+                return r;
+
+        if (a == DEVICE_ACTION_MOVE) {
+                log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a));
+
+                r = sd_device_get_sysname(device, &new_name);
+                if (r < 0)
+                        return log_device_error_errno(device, r, "Failed to get sysname: %m");
+        } else {
+                r = link_config_generate_new_name(ctx, config, device, &new_name);
+                if (r < 0)
+                        return r;
+        }
+
+        r = link_config_apply_alternative_names(&ctx->rtnl, config, device, new_name);
+        if (r < 0)
+                return r;
 
+        *ret_name = new_name;
         return 0;
 }
 
index 827ebf436c715bb12bcdc774807879ca7139a9a1..8b5801c003fd15070099b64df7dab10980fd0021 100644 (file)
@@ -77,8 +77,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename);
 int link_config_load(link_config_ctx *ctx);
 bool link_config_should_reload(link_config_ctx *ctx);
 
-int link_config_get(link_config_ctx *ctx, sd_device *device, struct link_config **ret);
-int link_config_apply(link_config_ctx *ctx, struct link_config *config, sd_device *device, const char **name);
+int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret);
+int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name);
 int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret);
 
 const char *name_policy_to_string(NamePolicy p) _const_;
index bb08da28b52273fbe1ddcc80a51c3f5e8a4bd3cd..9c33a560a8ccbfc0dc3f1399f36be8fd5e1d5501 100644 (file)
@@ -236,7 +236,7 @@ static int get_file_options(const char *vendor, const char *model,
                         retval = -1;
                         break;
                 }
-                if (vendor == NULL) {
+                if (!vendor) {
                         if (!vendor_in)
                                 break;
                 } else if (vendor_in &&
index eb980cb980584b3261fedff94a34a1e8ea4db4d9..48146105e043a916f8df37ed5681cc5735828826 100644 (file)
@@ -110,10 +110,8 @@ static const char* parse_token(const char *current, int32_t *val_out) {
 static int override_abs(sd_device *dev, int fd, unsigned evcode, const char *value) {
         struct input_absinfo absinfo;
         const char *next;
-        int r;
 
-        r = ioctl(fd, EVIOCGABS(evcode), &absinfo);
-        if (r < 0)
+        if (ioctl(fd, EVIOCGABS(evcode), &absinfo) < 0)
                 return log_device_error_errno(dev, errno, "Failed to call EVIOCGABS");
 
         next = parse_token(value, &absinfo.minimum);
@@ -122,12 +120,12 @@ static int override_abs(sd_device *dev, int fd, unsigned evcode, const char *val
         next = parse_token(next, &absinfo.fuzz);
         next = parse_token(next, &absinfo.flat);
         if (!next)
-                return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Failed to parse EV_ABS override '%s'", value);
+                return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "Failed to parse EV_ABS override '%s'", value);
 
         log_device_debug(dev, "keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32,
                          evcode, absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat);
-        r = ioctl(fd, EVIOCSABS(evcode), &absinfo);
-        if (r < 0)
+        if (ioctl(fd, EVIOCSABS(evcode), &absinfo) < 0)
                 return log_device_error_errno(dev, errno, "Failed to call EVIOCSABS");
 
         return 0;
index f070c1dc9cecfa206a81435e1eabf229352067d6..d3db37a8e013a050d283e361271dea178804f6ef 100644 (file)
@@ -243,9 +243,29 @@ static bool is_pci_ari_enabled(sd_device *dev) {
         return streq(a, "1");
 }
 
+static bool is_pci_bridge(sd_device *dev) {
+        const char *v, *p;
+
+        if (sd_device_get_sysattr_value(dev, "modalias", &v) < 0)
+                return false;
+
+        if (!startswith(v, "pci:"))
+                return false;
+
+        p = strrchr(v, 's');
+        if (!p)
+                return false;
+        if (p[1] != 'c')
+                return false;
+
+        /* PCI device subclass 04 corresponds to PCI bridge */
+        return strneq(p + 2, "04", 2);
+}
+
 static int dev_pci_slot(sd_device *dev, struct netnames *names) {
         unsigned long dev_port = 0;
-        unsigned domain, bus, slot, func, hotplug_slot = 0;
+        unsigned domain, bus, slot, func;
+        int hotplug_slot = -1;
         size_t l;
         char *s;
         const char *sysname, *attr, *port_name = NULL, *syspath;
@@ -326,14 +346,14 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) {
                         continue;
 
                 FOREACH_DIRENT_ALL(dent, dir, break) {
-                        unsigned i;
+                        int i;
                         char str[PATH_MAX];
                         _cleanup_free_ char *address = NULL;
 
                         if (dot_or_dot_dot(dent->d_name))
                                 continue;
 
-                        r = safe_atou_full(dent->d_name, 10, &i);
+                        r = safe_atoi(dent->d_name, &i);
                         if (r < 0 || i <= 0)
                                 continue;
 
@@ -342,10 +362,18 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) {
                             read_one_line_file(str, &address) >= 0 &&
                             startswith(sysname, address)) {
                                 hotplug_slot = i;
+
+                                /* We found the match between PCI device and slot. However, we won't use the
+                                 * slot index if the device is a PCI bridge, because it can have other child
+                                 * devices that will try to claim the same index and that would create name
+                                 * collision. */
+                                if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev))
+                                        hotplug_slot = 0;
+
                                 break;
                         }
                 }
-                if (hotplug_slot > 0)
+                if (hotplug_slot >= 0)
                         break;
                 if (sd_device_get_parent_with_subsystem_devtype(hotplug_slot_dev, "pci", NULL, &hotplug_slot_dev) < 0)
                         break;
index dafe3da2511b39ac55f701160277a3614f3adba6..8401691659554a42521290e3791be36517a3e83b 100644 (file)
@@ -58,7 +58,6 @@ struct udev_ctrl {
 int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
         _cleanup_close_ int sock = -1;
         struct udev_ctrl *uctrl;
-        int r;
 
         assert(ret);
 
@@ -79,14 +78,6 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
                 .bound = fd >= 0,
         };
 
-        /*
-         * FIXME: remove it as soon as we can depend on this:
-         *   http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=90c6bd34f884cd9cee21f1d152baf6c18bcac949
-         */
-        r = setsockopt_int(uctrl->sock, SOL_SOCKET, SO_PASSCRED, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to set SO_PASSCRED: %m");
-
         uctrl->saddr.un = (struct sockaddr_un) {
                 .sun_family = AF_UNIX,
                 .sun_path = "/run/udev/control",
@@ -355,10 +346,6 @@ int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int in
         return 0;
 }
 
-static int udev_ctrl_wait_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        return sd_event_exit(sd_event_source_get_event(s), 0);
-}
-
 int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
         _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
         int r;
@@ -385,7 +372,7 @@ int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
                         return r;
         }
 
-        r = sd_event_add_io(uctrl->event, &source_io, uctrl->sock, EPOLLIN, udev_ctrl_wait_io_handler, NULL);
+        r = sd_event_add_io(uctrl->event, &source_io, uctrl->sock, EPOLLIN, NULL, INT_TO_PTR(0));
         if (r < 0)
                 return r;
 
index 7c78b4c680da8d5dff93e1396c01e62f492e853a..ede8e3aef72ae3fa840c87ec9eba53186bb599ec 100644 (file)
@@ -940,16 +940,9 @@ static void event_execute_rules_on_remove(
                 (void) udev_node_remove(dev);
 }
 
-static int udev_event_on_move(UdevEvent *event) {
-        sd_device *dev = event->dev;
+static int udev_event_on_move(sd_device *dev) {
         int r;
 
-        if (sd_device_get_devnum(dev, NULL) < 0) {
-                r = device_copy_properties(dev, event->dev_db_clone);
-                if (r < 0)
-                        log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m");
-        }
-
         /* Drop previously added property */
         r = device_add_property(dev, "ID_RENAMING", NULL);
         if (r < 0)
@@ -1017,7 +1010,7 @@ int udev_event_execute_rules(UdevEvent *event,
                 (void) udev_watch_end(event->dev_db_clone);
 
         if (action == DEVICE_ACTION_MOVE) {
-                r = udev_event_on_move(event);
+                r = udev_event_on_move(event->dev);
                 if (r < 0)
                         return r;
         }
index bc259dd6f678b23353644dcf521eb6eea2d99cb0..2cc26d29fa64957f788caec59a8c564db3f8057f 100644 (file)
@@ -273,9 +273,10 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
                                   mode_t mode, uid_t uid, gid_t gid,
                                   OrderedHashmap *seclabel_list) {
         const char *devnode, *subsystem, *id_filename = NULL;
+        bool apply_mode, apply_uid, apply_gid;
+        _cleanup_close_ int node_fd = -1;
         struct stat stats;
         dev_t devnum;
-        bool apply_mode, apply_uid, apply_gid;
         int r;
 
         assert(dev);
@@ -296,16 +297,25 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
         else
                 mode |= S_IFCHR;
 
-        if (lstat(devnode, &stats) < 0) {
-                if (errno == ENOENT)
-                        return 0; /* this is necessarily racey, so ignore missing the device */
-                return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode);
+        node_fd = open(devnode, O_PATH|O_NOFOLLOW|O_CLOEXEC);
+        if (node_fd < 0) {
+                if (errno == ENOENT) {
+                        log_device_debug_errno(dev, errno, "Device node %s is missing, skipping handling.", devnode);
+                        return 0; /* This is necessarily racey, so ignore missing the device */
+                }
+
+                return log_device_debug_errno(dev, errno, "Cannot open node %s: %m", devnode);
         }
 
-        if ((mode != MODE_INVALID && (stats.st_mode & S_IFMT) != (mode & S_IFMT)) || stats.st_rdev != devnum)
-                return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
-                                              "Found node '%s' with non-matching devnum %s, skip handling",
-                                              devnode, id_filename);
+        if (fstat(node_fd, &stats) < 0)
+                return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode);
+
+        if ((mode != MODE_INVALID && (stats.st_mode & S_IFMT) != (mode & S_IFMT)) || stats.st_rdev != devnum) {
+                log_device_debug(dev, "Found node '%s' with non-matching devnum %s, skipping handling.",
+                                 devnode, id_filename);
+                return 0; /* We might process a device that already got replaced by the time we have a look
+                           * at it, handle this gracefully and step away. */
+        }
 
         apply_mode = mode != MODE_INVALID && (stats.st_mode & 0777) != (mode & 0777);
         apply_uid = uid_is_valid(uid) && stats.st_uid != uid;
@@ -322,7 +332,7 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
                                          gid_is_valid(gid) ? gid : stats.st_gid,
                                          mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
 
-                        r = chmod_and_chown(devnode, mode, uid, gid);
+                        r = fchmod_and_chown(node_fd, mode, uid, gid);
                         if (r < 0)
                                 log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
                                                       "Failed to set owner/mode of %s to uid=" UID_FMT
@@ -345,7 +355,7 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
                         if (streq(name, "selinux")) {
                                 selinux = true;
 
-                                q = mac_selinux_apply(devnode, label);
+                                q = mac_selinux_apply_fd(node_fd, devnode, label);
                                 if (q < 0)
                                         log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
                                                               "SECLABEL: failed to set SELinux label '%s': %m", label);
@@ -355,7 +365,7 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
                         } else if (streq(name, "smack")) {
                                 smack = true;
 
-                                q = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label);
+                                q = mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, label);
                                 if (q < 0)
                                         log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
                                                               "SECLABEL: failed to set SMACK label '%s': %m", label);
@@ -368,13 +378,15 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
 
                 /* set the defaults */
                 if (!selinux)
-                        (void) mac_selinux_fix(devnode, LABEL_IGNORE_ENOENT);
+                        (void) mac_selinux_fix_fd(node_fd, devnode, LABEL_IGNORE_ENOENT);
                 if (!smack)
-                        (void) mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL);
+                        (void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL);
         }
 
         /* always update timestamp when we re-use the node, like on media change events */
-        (void) utimensat(AT_FDCWD, devnode, NULL, 0);
+        r = futimens_opath(node_fd, NULL);
+        if (r < 0)
+                log_device_debug_errno(dev, r, "Failed to adjust timestamp of node %s: %m", devnode);
 
         return r;
 }
index 437429a3e0b09cf0b6ca88682e776657dc4d18f6..7e029927fd0d45960f5933c64fe773b36c7efafd 100644 (file)
@@ -480,7 +480,7 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
                 if (len > 0 && !isspace(value[len - 1]))
                         remove_trailing_whitespace = true;
 
-                subst_type = rule_get_substitution_type((const char*) data);
+                subst_type = rule_get_substitution_type(data);
         }
 
         token = new(UdevRuleToken, 1);
@@ -1386,7 +1386,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
         assert(dev);
         assert(event);
 
-        name = (const char*) token->data;
+        name = token->data;
 
         switch (token->attr_subst_type) {
         case SUBST_TYPE_FORMAT:
@@ -1585,7 +1585,7 @@ static int udev_rule_apply_token_to_event(
         case TK_M_NAME:
                 return token_match_string(token, event->name);
         case TK_M_ENV:
-                if (sd_device_get_property_value(dev, (const char*) token->data, &val) < 0)
+                if (sd_device_get_property_value(dev, token->data, &val) < 0)
                         val = hashmap_get(properties_list, token->data);
 
                 return token_match_string(token, val);
@@ -1630,7 +1630,7 @@ static int udev_rule_apply_token_to_event(
         case TK_M_SYSCTL: {
                 _cleanup_free_ char *value = NULL;
 
-                (void) udev_event_apply_format(event, (const char*) token->data, buf, sizeof(buf), false);
+                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false);
                 r = sysctl_read(sysctl_normalize(buf), &value);
                 if (r < 0 && r != -ENOENT)
                         return log_rule_error_errno(dev, rules, r, "Failed to read sysctl '%s': %m", buf);
@@ -1957,7 +1957,7 @@ static int udev_rule_apply_token_to_event(
                 _cleanup_free_ char *name = NULL, *label = NULL;
                 char label_str[UTIL_LINE_SIZE] = {};
 
-                name = strdup((const char*) token->data);
+                name = strdup(token->data);
                 if (!name)
                         return log_oom();
 
@@ -1984,7 +1984,7 @@ static int udev_rule_apply_token_to_event(
                 break;
         }
         case TK_A_ENV: {
-                const char *name = (const char*) token->data;
+                const char *name = token->data;
                 char value_new[UTIL_NAME_SIZE], *p = value_new;
                 size_t l = sizeof(value_new);
 
@@ -2097,7 +2097,7 @@ static int udev_rule_apply_token_to_event(
                 break;
         }
         case TK_A_ATTR: {
-                const char *key_name = (const char*) token->data;
+                const char *key_name = token->data;
                 char value[UTIL_NAME_SIZE];
 
                 if (util_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 &&
@@ -2120,7 +2120,7 @@ static int udev_rule_apply_token_to_event(
         case TK_A_SYSCTL: {
                 char value[UTIL_NAME_SIZE];
 
-                (void) udev_event_apply_format(event, (const char*) token->data, buf, sizeof(buf), false);
+                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false);
                 (void) udev_event_apply_format(event, token->value, value, sizeof(value), false);
                 sysctl_normalize(buf);
                 log_rule_debug(dev, rules, "SYSCTL '%s' writing '%s'", buf, value);
index 39113d2fa23294b5ad3dc963681b42389c52f7b3..a588d18fd117b1637af09f7729adf66b902072f5 100644 (file)
@@ -45,13 +45,14 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_s
 
                 r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER);
                 if (r < 0) {
-                        bool ignore = IN_SET(r, -ENOENT, -EACCES, -ENODEV, -EROFS);
+                        bool ignore = IN_SET(r, -ENOENT, -ENODEV);
 
                         log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r,
                                        "Failed to write '%s' to '%s'%s: %m",
                                        action, filename, ignore ? ", ignoring" : "");
-                        if (r == -EROFS)
-                                return 0; /* Read only filesystem. Return earlier. */
+                        if (IN_SET(r, -EACCES, -EROFS))
+                                /* Inovoked by unpriviledged user, or read only filesystem. Return earlier. */
+                                return r;
                         if (ret == 0 && !ignore)
                                 ret = r;
                         continue;
index 557982b23dfa896b9c5681c17e2edda0110bb936..bc21115ebdd953888368330865ae927714e1149a 100644 (file)
@@ -3,11 +3,73 @@
 #include <errno.h>
 
 #include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
 #include "device-private.h"
 #include "path-util.h"
 #include "udevadm-util.h"
 #include "unit-name.h"
 
+static int find_device_from_path(const char *path, sd_device **ret) {
+        if (path_startswith(path, "/sys/"))
+                return sd_device_new_from_syspath(ret, path);
+
+        if (path_startswith(path, "/dev/")) {
+                struct stat st;
+
+                if (stat(path, &st) < 0)
+                        return -errno;
+
+                return device_new_from_stat_rdev(ret, &st);
+        }
+
+        return -EINVAL;
+}
+
+static int find_device_from_unit(const char *unit_name, sd_device **ret) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        _cleanup_free_ char *unit_path = NULL, *syspath = NULL;
+        int r;
+
+        if (!unit_name_is_valid(unit_name, UNIT_NAME_PLAIN))
+                return -EINVAL;
+
+        if (unit_name_to_type(unit_name) != UNIT_DEVICE)
+                return -EINVAL;
+
+        r = bus_connect_system_systemd(&bus);
+        if (r < 0) {
+                _cleanup_free_ char *path = NULL;
+
+                log_debug_errno(r, "Failed to open connection to systemd, using unit name as syspath: %m");
+
+                r = unit_name_to_path(unit_name, &path);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to convert \"%s\" to a device path: %m", unit_name);
+
+                return find_device_from_path(path, ret);
+        }
+
+        unit_path = unit_dbus_path_from_name(unit_name);
+        if (!unit_path)
+                return -ENOMEM;
+
+        r = sd_bus_get_property_string(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        unit_path,
+                        "org.freedesktop.systemd1.Device",
+                        "SysFSPath",
+                        &error,
+                        &syspath);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get SysFSPath= dbus property for %s: %s",
+                                       unit_name, bus_error_message(&error, r));
+
+        return sd_device_new_from_syspath(ret, syspath);
+}
+
 int find_device(const char *id, const char *prefix, sd_device **ret) {
         _cleanup_free_ char *path = NULL;
         int r;
@@ -24,26 +86,10 @@ int find_device(const char *id, const char *prefix, sd_device **ret) {
         } else {
                 /* In cases where the argument is generic (no prefix specified),
                  * check if the argument looks like a device unit name. */
-                if (unit_name_is_valid(id, UNIT_NAME_PLAIN) &&
-                    unit_name_to_type(id) == UNIT_DEVICE) {
-                        r = unit_name_to_path(id, &path);
-                        if (r < 0)
-                                return log_debug_errno(r, "Failed to convert \"%s\" to a device path: %m", id);
-                        id = path;
-                }
+                r = find_device_from_unit(id, ret);
+                if (r >= 0)
+                        return r;
         }
 
-        if (path_startswith(id, "/sys/"))
-                return sd_device_new_from_syspath(ret, id);
-
-        if (path_startswith(id, "/dev/")) {
-                struct stat st;
-
-                if (stat(id, &st) < 0)
-                        return -errno;
-
-                return device_new_from_stat_rdev(ret, &st);
-        }
-
-        return -EINVAL;
+        return find_device_from_path(id, ret);
 }
index d6415ad57e9a51f9cda531eef70ca6d3dc0133de..18079d363d8476e93d0f749d39b735ee9c41ee71 100644 (file)
@@ -459,6 +459,43 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
                 return -ENOMEM;
 
         r = worker_lock_block_device(dev, &fd_lock);
+        if (r == -EAGAIN) {
+                /* So this is a block device and the device is locked currently via the BSD advisory locks —
+                 * someone else is exclusively using it. This means we don't run our udev rules now, to not
+                 * interfere. However we want to know when the device is unlocked again, and retrigger the
+                 * device again then, so that the rules are run eventually. For that we use IN_CLOSE_WRITE
+                 * inotify watches (which isn't exactly the same as waiting for the BSD locks to release, but
+                 * not totally off, as long as unlock+close() is done together, as it usually is).
+                 *
+                 * (The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING)
+                 *
+                 * There's a bit of a chicken and egg problem here for this however: inotify watching is
+                 * supposed to be enabled via an option set via udev rules (OPTIONS+="watch"). If we skip the
+                 * udev rules here however (as we just said we do), we would thus never see that specific
+                 * udev rule, and thus never turn on inotify watching. But in order to catch up eventually
+                 * and run them we we need the inotify watching: hence a classic chicken and egg problem.
+                 *
+                 * Our way out here: if we see the block device locked, unconditionally watch the device via
+                 * inotify, regardless of any explicit request via OPTIONS+="watch". Thus, a device that is
+                 * currently locked via the BSD file locks will be treated as if we ran a single udev rule
+                 * only for it: the one that turns on inotify watching for it. If we eventually see the
+                 * inotify IN_CLOSE_WRITE event, and then run the rules after all and we then realize that
+                 * this wasn't actually requested (i.e. no OPTIONS+="watch" set) we'll simply turn off the
+                 * watching again (see below). Effectively this means: inotify watching is now enabled either
+                 * a) when the udev rules say so, or b) while the device is locked.
+                 *
+                 * Worst case scenario hence: in the (unlikely) case someone locked the device and we clash
+                 * with that we might do inotify watching for a brief moment for a device where we actually
+                 * weren't supposed to. But that shouldn't be too bad, in particular as BSD locks being taken
+                 * on a block device is kinda an indication that the inotify logic is desired too, to some
+                 * degree — they go hand-in-hand after all. */
+
+                log_device_debug(dev, "Block device is currently locked, installing watch to wait until the lock is released.");
+                (void) udev_watch_begin(dev);
+
+                /* Now the watch is installed, let's lock the device again, maybe in the meantime things changed */
+                r = worker_lock_block_device(dev, &fd_lock);
+        }
         if (r < 0)
                 return r;
 
@@ -475,13 +512,14 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
                 /* in case rtnl was initialized */
                 manager->rtnl = sd_netlink_ref(udev_event->rtnl);
 
-        /* apply/restore inotify watch */
+        /* apply/restore/end inotify watch */
         if (udev_event->inotify_watch) {
                 (void) udev_watch_begin(dev);
                 r = device_update_db(dev);
                 if (r < 0)
                         return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m");
-        }
+        } else
+                (void) udev_watch_end(dev);
 
         log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) processed",
                          seqnum, device_action_to_string(action));
index e9d589e0e53045eaae06b213b39f1b0ce21c182c..92c348d83bc8003c25867c92fdb04a660dc75f99 100644 (file)
@@ -31,8 +31,8 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
 
         r = write_string_file_atomic_label_ts(path, message, ts);
         if (r == -EROFS)
-                return log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
-        if (r < 0)
+                log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
+        else if (r < 0)
                 return log_error_errno(r, "Failed to write \"%s\": %m", path);
         return 0;
 }
index 0485c90fc923c4e224b7e89a90900516603f2c01..da5e79dcff5d014a22219f66ccb833a22631caba 100644 (file)
@@ -28,6 +28,7 @@ XdgAutostartService* xdg_autostart_service_free(XdgAutostartService *s) {
 
         free(s->type);
         free(s->exec_string);
+        free(s->working_directory);
 
         strv_free(s->only_show_in);
         strv_free(s->not_show_in);
@@ -321,6 +322,7 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) {
         const ConfigTableItem items[] = {
                 { "Desktop Entry", "Name",                      xdg_config_parse_string, 0, &service->description},
                 { "Desktop Entry", "Exec",                      xdg_config_parse_string, 0, &service->exec_string},
+                { "Desktop Entry", "Path",                      xdg_config_parse_string, 0, &service->working_directory},
                 { "Desktop Entry", "TryExec",                   xdg_config_parse_string, 0, &service->try_exec},
                 { "Desktop Entry", "Type",                      xdg_config_parse_string, 0, &service->type},
                 { "Desktop Entry", "OnlyShowIn",                xdg_config_parse_strv, 0,   &service->only_show_in},
@@ -338,9 +340,12 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) {
                 { "Desktop Entry", "GenericName", NULL, 0, NULL},
                 { "Desktop Entry", "Icon", NULL, 0, NULL},
                 { "Desktop Entry", "Keywords", NULL, 0, NULL},
+                { "Desktop Entry", "MimeType", NULL, 0, NULL},
                 { "Desktop Entry", "NoDisplay", NULL, 0, NULL},
                 { "Desktop Entry", "StartupNotify", NULL, 0, NULL},
+                { "Desktop Entry", "StartupWMClass", NULL, 0, NULL},
                 { "Desktop Entry", "Terminal", NULL, 0, NULL},
+                { "Desktop Entry", "URL", NULL, 0, NULL},
                 { "Desktop Entry", "Version", NULL, 0, NULL},
                 {}
         };
@@ -483,7 +488,7 @@ static int xdg_autostart_generate_desktop_condition(
 
                 r = find_executable(test_binary, &gnome_autostart_condition_path);
                 if (r < 0) {
-                        log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r,
+                        log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
                                        "%s not found: %m", test_binary);
                         fprintf(f, "# ExecCondition using %s skipped due to missing binary.\n", test_binary);
                         return r;
@@ -514,18 +519,18 @@ int xdg_autostart_service_generate_unit(
 
         /* Nothing to do for hidden services. */
         if (service->hidden) {
-                log_info("Not generating service for XDG autostart %s, it is hidden.", service->name);
+                log_debug("Not generating service for XDG autostart %s, it is hidden.", service->name);
                 return 0;
         }
 
         if (service->systemd_skip) {
-                log_info("Not generating service for XDG autostart %s, should be skipped by generator.", service->name);
+                log_debug("Not generating service for XDG autostart %s, should be skipped by generator.", service->name);
                 return 0;
         }
 
         /* Nothing to do if type is not Application. */
         if (!streq_ptr(service->type, "Application")) {
-                log_info("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name);
+                log_debug("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name);
                 return 0;
         }
 
@@ -541,7 +546,7 @@ int xdg_autostart_service_generate_unit(
         if (service->try_exec) {
                 r = find_executable(service->try_exec, NULL);
                 if (r < 0) {
-                        log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r,
+                        log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
                                        "Not generating service for XDG autostart %s, could not find TryExec= binary %s: %m",
                                        service->name, service->try_exec);
                         return 0;
@@ -558,8 +563,8 @@ int xdg_autostart_service_generate_unit(
 
         if (service->gnome_autostart_phase) {
                 /* There is no explicit value for the "Application" phase. */
-                log_info("Not generating service for XDG autostart %s, startup phases are not supported.",
-                         service->name);
+                log_debug("Not generating service for XDG autostart %s, startup phases are not supported.",
+                          service->name);
                 return 0;
         }
 
@@ -599,13 +604,23 @@ int xdg_autostart_service_generate_unit(
 
         fprintf(f,
                 "\n[Service]\n"
-                "Type=simple\n"
+                "Type=exec\n"
                 "ExecStart=:%s\n"
                 "Restart=no\n"
                 "TimeoutSec=5s\n"
                 "Slice=app.slice\n",
                 exec_start);
 
+        if (service->working_directory) {
+                _cleanup_free_ char *e_working_directory = NULL;
+
+                e_working_directory = cescape(service->working_directory);
+                if (!e_working_directory)
+                        return log_oom();
+
+                fprintf(f, "WorkingDirectory=-%s\n", e_working_directory);
+        }
+
         /* Generate an ExecCondition to check $XDG_CURRENT_DESKTOP */
         if (!strv_isempty(service->only_show_in) || !strv_isempty(service->not_show_in)) {
                 _cleanup_free_ char *only_show_in = NULL, *not_show_in = NULL, *e_only_show_in = NULL, *e_not_show_in = NULL;
index 685f97824e3dd539254bb4630ce31eee62261cef..8cf07ef64a5f7b57ece236bd5f0067d6707cb78b 100644 (file)
@@ -10,6 +10,7 @@ typedef struct XdgAutostartService {
 
         char *type; /* Purely as an assertion check */
         char *exec_string;
+        char *working_directory;
 
         char **only_show_in;
         char **not_show_in;
index da76fd71d6a2e3da0602bcc4fafc6e4f8251fc5f..4338756efd85136a12f4eb82698d9fe94ff8421b 100644 (file)
 # See systemd-coredump(8) and core(5).
 kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h
 
+# Allow that 16 coredumps are dispatched in parallel by the kernel. We want to
+# be able to collect process metadata from /proc/%P/ while processing
+# coredumps, and thus need to make sure the crashed processes are not reaped
+# until we finished collecting what we need. The kernel default for this sysctl
+# is "0" which means the kernel doesn't wait for userspace processes to finish
+# processing before reaping the crashed processes — by setting this higher the
+# kernel will delay reaping until we are done, but only for the specified
+# number of crashes in parallel. The value of 16 is chosen to match
+# systemd-coredump.socket's MaxConnections= value.
+kernel.core_pipe_limit=16
+
 # Also dump processes executing a set-user-ID/set-group-ID program that is
 # owned by a user/group other than the real user/group ID of the process, or
 # a program that has file capabilities. ("2" is called "suidsafe" in core(5)).
index eb99957e2f970daa952a2aeaa8cabea73556cbef..146f922bed0ec1dd0579a62c4039cba2dacc9ddb 100644 (file)
@@ -2,8 +2,6 @@
 
 in_files = ['basic.conf']
 
-enable_sysusers = conf.get('ENABLE_SYSUSERS') == 1
-
 foreach file : in_files
         gen = configure_file(
                 input : file + '.in',
index ef5a3cb6198ca0f6ba2866085ceb8e751060da92..fdfdcf553c3fa622982a1758bd12188ec8323d66 100644 (file)
@@ -9,6 +9,9 @@ g systemd-journal   - -
 m4_ifdef(`ENABLE_NETWORKD',
 u systemd-network   - "systemd Network Management"
 )m4_dnl
+m4_ifdef(`ENABLE_OOMD',
+u systemd-oom       - "systemd Userspace OOM Killer"
+)m4_dnl
 m4_ifdef(`ENABLE_RESOLVE',
 u systemd-resolve   - "systemd Resolver"
 )m4_dnl
index 34c7ab3f7de6082c1f04ac37ddfbea541925ffd5..5d9e498c51a0fb2b501a6edac65b8eccea15a357 100644 (file)
@@ -120,3 +120,12 @@ https://wiki.debian.org/ArchitectureSpecificsMemo
 
 For PRs that fix a currently deny-listed test, the PR should include removal
 of the deny-list file.
+
+In case a test fails, the full set of artifacts, including the journal of the
+failed run, can be downloaded from the artifacts.tar.gz archive which will be
+reachable in the same URL parent directory as the logs.gz that gets linked on
+the Github CI status.
+
+To add new dependencies or new binaries to the packages used during the tests,
+a merge request can be sent to: https://salsa.debian.org/systemd-team/systemd
+targeting the 'upstream-ci' branch.
diff --git a/test/TEST-21-SYSUSERS/Makefile b/test/TEST-21-SYSUSERS/Makefile
deleted file mode 120000 (symlink)
index e9f93b1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-21-SYSUSERS/test-10.expected-group b/test/TEST-21-SYSUSERS/test-10.expected-group
deleted file mode 100644 (file)
index 1c92158..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-u1:x:300:u2
-u2:x:SYSTEM_UID_MAX:
diff --git a/test/TEST-21-SYSUSERS/test-10.expected-passwd b/test/TEST-21-SYSUSERS/test-10.expected-passwd
deleted file mode 100644 (file)
index ca2d764..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-u1:x:300:300::/:NOLOGIN
-u2:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN
diff --git a/test/TEST-21-SYSUSERS/test-14.expected-passwd b/test/TEST-21-SYSUSERS/test-14.expected-passwd
deleted file mode 100644 (file)
index 62ed4f5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-aaa:x:SYSTEM_UID_MAX:987::/:NOLOGIN
diff --git a/test/TEST-21-SYSUSERS/test-6.expected-group b/test/TEST-21-SYSUSERS/test-6.expected-group
deleted file mode 100644 (file)
index 499c900..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-g1:x:111:
-u1:x:SYSTEM_UID_MAX:
diff --git a/test/TEST-21-SYSUSERS/test-6.expected-passwd b/test/TEST-21-SYSUSERS/test-6.expected-passwd
deleted file mode 100644 (file)
index ba55a13..0000000
+++ /dev/null
@@ -1 +0,0 @@
-u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN
diff --git a/test/TEST-21-SYSUSERS/test-8.expected-passwd b/test/TEST-21-SYSUSERS/test-8.expected-passwd
deleted file mode 100644 (file)
index 23e99f0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-username:x:SYSTEM_UID_MAX:300::/:NOLOGIN
diff --git a/test/TEST-21-SYSUSERS/test-9.expected-passwd b/test/TEST-21-SYSUSERS/test-9.expected-passwd
deleted file mode 100644 (file)
index 0bffbcd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-user1:x:300:300::/:NOLOGIN
-user2:x:SYSTEM_UID_MAX:300::/:NOLOGIN
diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh
deleted file mode 100755 (executable)
index 3b37f7e..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/env bash
-set -e
-TEST_DESCRIPTION="Sysuser-related tests"
-IMAGE_NAME="sysusers"
-. $TEST_BASE_DIR/test-functions
-
-test_setup() {
-    mkdir -p $TESTDIR/etc/sysusers.d $TESTDIR/usr/lib/sysusers.d $TESTDIR/tmp
-}
-
-prepare_testdir() {
-    rm -f $TESTDIR/etc/*{passwd,group,shadow}
-    for i in $1.initial-{passwd,group,shadow}; do
-        test -f $i && cp $i $TESTDIR/etc/${i#*.initial-}
-    done
-    return 0
-}
-
-preprocess() {
-    in="$1"
-
-    # see meson.build how to extract this. gcc -E was used before to
-    # get this value from config.h, however the autopkgtest fails with
-    # it
-    [[ -e /etc/login.defs ]] && login_defs_file="/etc/login.defs" || login_defs_file="/usr/etc/login.defs"
-    SYSTEM_UID_MAX=$(awk 'BEGIN { uid=999 } /^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }' $login_defs_file)
-    SYSTEM_GID_MAX=$(awk 'BEGIN { gid=999 } /^\s*SYS_GID_MAX\s+/ { gid=$2 } END { print gid }' $login_defs_file)
-
-    # we can't rely on config.h to get the nologin path, as autopkgtest
-    # uses pre-compiled binaries, so extract it from the systemd-sysusers
-    # binary which we are about to execute
-    NOLOGIN=$(strings $(type -p systemd-sysusers) | grep nologin)
-
-    sed -e "s/SYSTEM_UID_MAX/${SYSTEM_UID_MAX}/g" \
-        -e "s/SYSTEM_GID_MAX/${SYSTEM_GID_MAX}/g" \
-        -e "s#NOLOGIN#${NOLOGIN}#g" "$in"
-}
-
-compare() {
-    if ! diff -u $TESTDIR/etc/passwd <(preprocess ${1%.*}.expected-passwd); then
-        echo "**** Unexpected output for $f"
-        exit 1
-    fi
-
-    if ! diff -u $TESTDIR/etc/group <(preprocess ${1%.*}.expected-group); then
-        echo "**** Unexpected output for $f $2"
-        exit 1
-    fi
-}
-
-test_run() {
-    # ensure our build of systemd-sysusers is run
-    PATH=${BUILD_DIR}:$PATH
-
-    rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
-
-    # happy tests
-    for f in test-*.input; do
-        echo "*** Running $f"
-        prepare_testdir ${f%.input}
-        cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
-        systemd-sysusers --root=$TESTDIR
-
-        compare $f ""
-    done
-
-    for f in test-*.input; do
-        echo "*** Running $f on stdin"
-        prepare_testdir ${f%.input}
-        touch $TESTDIR/etc/sysusers.d/test.conf
-        cat $f | systemd-sysusers --root=$TESTDIR -
-
-        compare $f "on stdin"
-    done
-
-    for f in test-*.input; do
-        echo "*** Running $f on stdin with --replace"
-        prepare_testdir ${f%.input}
-        touch $TESTDIR/etc/sysusers.d/test.conf
-        # this overrides test.conf which is masked on disk
-        cat $f | systemd-sysusers --root=$TESTDIR --replace=/etc/sysusers.d/test.conf -
-        # this should be ignored
-        cat test-1.input | systemd-sysusers --root=$TESTDIR --replace=/usr/lib/sysusers.d/test.conf -
-
-        compare $f "on stdin with --replace"
-    done
-
-    # test --inline
-    echo "*** Testing --inline"
-    prepare_testdir
-    # copy a random file to make sure it is ignored
-    cp $f $TESTDIR/etc/sysusers.d/confuse.conf
-    systemd-sysusers --root=$TESTDIR --inline \
-                     "u     u1   222 -     - /bin/zsh" \
-                     "g     g1   111"
-
-    compare inline "(--inline)"
-
-    # test --replace
-    echo "*** Testing --inline with --replace"
-    prepare_testdir
-    # copy a random file to make sure it is ignored
-    cp $f $TESTDIR/etc/sysusers.d/confuse.conf
-    systemd-sysusers --root=$TESTDIR \
-                     --inline \
-                     --replace=/etc/sysusers.d/confuse.conf \
-                     "u     u1   222 -     - /bin/zsh" \
-                     "g     g1   111"
-
-    compare inline "(--inline --replace=…)"
-
-    rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
-
-    # tests for error conditions
-    for f in unhappy-*.input; do
-        echo "*** Running test $f"
-        prepare_testdir ${f%.input}
-        cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
-        systemd-sysusers --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/tmp/err
-        if ! diff -u $TESTDIR/tmp/err  ${f%.*}.expected-err; then
-            echo "**** Unexpected error output for $f"
-            cat $TESTDIR/tmp/err
-            exit 1
-        fi
-    done
-}
-
-do_test "$@"
index 4feafc04d708246c4c659180e9bfa65d666c7075..ddf6db9735926517bbf38c64a7e6dac554f65783 100755 (executable)
@@ -1,9 +1,24 @@
 #!/usr/bin/env bash
 set -e
 TEST_DESCRIPTION="UDEV ID_RENAMING property"
+IMAGE_NAME="udev-id-renaming"
 TEST_NO_NSPAWN=1
 
 . $TEST_BASE_DIR/test-functions
 QEMU_TIMEOUT=300
 
+test_create_image() {
+    create_empty_image_rootdir
+
+    # Create what will eventually be our root filesystem onto an overlay
+    (
+        LOG_LEVEL=5
+        setup_basic_environment
+        mask_supporting_services
+
+        instmods dummy
+        generate_module_dependencies
+    )
+}
+
 do_test "$@" 29
index f274b73522b54a957ed3250e8fbb737b4668c4e9..073ca8c31b91bada4eb57dc138ee3207fc9d95ac 100755 (executable)
@@ -37,7 +37,7 @@ test_create_image() {
         )
         oldinitdir=$initdir
         export initdir=$TESTDIR/minimal
-        mkdir -p $initdir
+        mkdir -p $initdir/usr/lib $initdir/etc
         setup_basic_dirs
         install_basic_tools
         cp $os_release $initdir/usr/lib/os-release
index 901541fd327c09df1af07894db24f7bda8f4979e..e0b582d4f26b6bbb3792a9cd24e2c0d319605472 100644 (file)
@@ -92,7 +92,7 @@ gdb(1) będą ostrzegały o skróceniu pliku.
 Subject: Utworzono nową sesję @SESSION_ID@ dla użytkownika @USER_ID@
 Defined-By: systemd
 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Nowa sesja o identyfikatorze @SESSION_ID@ została utworzona dla użytkownika
 @USER_ID@.
@@ -103,7 +103,7 @@ Proces prowadzący sesji: @LEADER@.
 Subject: Zakończono sesję @SESSION_ID@
 Defined-By: systemd
 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Sesja o identyfikatorze @SESSION_ID@ została zakończona.
 
@@ -111,7 +111,7 @@ Sesja o identyfikatorze @SESSION_ID@ została zakończona.
 Subject: Dostępne jest nowe stanowisko @SEAT_ID@
 Defined-By: systemd
 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Nowe stanowisko @SEAT_ID@ zostało skonfigurowane i jest teraz dostępne.
 
@@ -119,7 +119,7 @@ Nowe stanowisko @SEAT_ID@ zostało skonfigurowane i jest teraz dostępne.
 Subject: Usunięto stanowisko @SEAT_ID@
 Defined-By: systemd
 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation: sd-login(3)
 
 Stanowisko @SEAT_ID@ zostało usunięte i nie jest już dostępne.
 
index 1494daa0c1b0e6854d6cbdb0ecd7d2e73a11d9ac..cb0c3205a0d3749da00814ed42800ff692cd8933 100644 (file)
@@ -137,6 +137,7 @@ SendVendorOption=
 RouteMetric=
 [DHCPv6PrefixDelegation]
 SubnetId=
+Announce=
 Assign=
 Token=
 [Route]
@@ -190,6 +191,7 @@ DNSOverTLS=
 Bond=
 IPv6ProxyNDP=
 DNS=
+DNSDefaultRoute=
 ActiveSlave=
 LLMNR=
 DNSSEC=
@@ -207,6 +209,7 @@ ConfigureWithoutCarrier=
 NTP=
 DHCP=
 Domains=
+IPv6SendRA=
 IPv6PrefixDelegation=
 VLAN=
 DHCPServer=
@@ -214,6 +217,7 @@ BindCarrier=
 VRF=
 IgnoreCarrierLoss=
 KeepConfiguration=
+DHCPv6PrefixDelegation=
 [IPv6Prefix]
 Prefix=
 OnLink=
@@ -270,11 +274,20 @@ InvertRule=
 Family=
 SuppressPrefixLength=
 User=
+[IPv6SendRA]
+RouterPreference=
+DNSLifetimeSec=
+DNS=
+RouterLifetimeSec=
+Domains=
+EmitDNS=
+EmitDomains=
+Managed=
+OtherInformation=
 [IPv6PrefixDelegation]
 RouterPreference=
 DNSLifetimeSec=
 DNS=
-DNSDefaultRoute=
 RouterLifetimeSec=
 Domains=
 EmitDNS=
index d12f82fa2d7997c0b3f215e477a373dd97e9888f..8b909f7d80996f17842c1d801d79779544a179cb 100755 (executable)
@@ -18,7 +18,7 @@ if [ ! -x "$SYSTEMD_HWDB" ]; then
     exit 1
 fi
 
-D=$(mktemp --directory)
+D=$(mktemp --tmpdir --directory "hwdb-test.XXXXXXXXXX")
 trap "rm -rf '$D'" EXIT INT QUIT PIPE
 mkdir -p "$D/etc/udev"
 ln -s "$ROOTDIR/hwdb.d" "$D/etc/udev/hwdb.d"
index 5d9fb5ab50925757e09af03f0f066dfd84033ded..5656abdf72a97df0277d351c9313aba86eb67789 100644 (file)
@@ -58,6 +58,21 @@ test_network_generator_conversion_sh = find_program('test-network-generator-conv
 
 ############################################################
 
+test_sysusers_dir = join_paths(meson.current_source_dir(), 'test-sysusers')
+
+test_sysusers_sh = configure_file(
+        input : 'test-sysusers.sh.in',
+        output : 'test-sysusers.sh',
+        configuration : substs)
+if install_tests and conf.get('ENABLE_SYSUSERS') == 1
+        install_data(test_sysusers_sh,
+                     install_dir : testsdir)
+        install_subdir('test-sysusers',
+                       install_dir : testdata_dir)
+endif
+
+############################################################
+
 rule_syntax_check_py = find_program('rule-syntax-check.py')
 if want_tests != 'false'
         test('rule-syntax-check',
index d0d083451821511d7e7c77b4f57dc3dc5f5c5ad1..50df69f1b01bcae8068e88addfa35330131ec926 100755 (executable)
@@ -17,7 +17,7 @@ for f in "$src"/test-*.input; do
     echo "*** Running $f"
 
     (
-        out=$(mktemp --directory)
+        out=$(mktemp --tmpdir --directory "test-network-generator-conversion.XXXXXXXXXX")
         trap "rm -rf '$out'" EXIT INT QUIT PIPE
 
         $generator --root "$out" -- $(cat $f)
diff --git a/test/test-network/conf/25-address-peer-ipv4.network b/test/test-network/conf/25-address-peer-ipv4.network
new file mode 100644 (file)
index 0000000..362ea25
--- /dev/null
@@ -0,0 +1,9 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+
+[Address]
+Address=100.64.0.1/32
+Peer=100.64.0.2/32
index f8119d13ee789e67f47f93eb77f537e041b8f625..506cdd2264db11653f6f8680a067f2b2c6fad0c1 100644 (file)
@@ -155,7 +155,6 @@ Address=10.3.3.98/16
 Address=10.3.3.99/16
 Address=10.3.3.100/16
 Address=10.3.3.101/16
-Address=10.3.3.101/16
 Address=10.3.3.102/16
 Address=10.3.3.103/16
 Address=10.3.3.104/16
index a4ba77a3e3f6bdb3eab2c58e48634674d304b8e1..bb485eb6b0dfa7de4b54b52ed93e60f3dc5d3336 100644 (file)
@@ -10,14 +10,11 @@ IPv4LLRoute=yes
 
 [Route]
 Destination=2001:1234:5:8fff:ff:ff:ff:ff/128
-Scope=link
 
 [Route]
 Destination=2001:1234:5:9fff:ff:ff:ff:ff/128
-Scope=link
 
 [Route]
-Destination=::/0
 Gateway=2001:1234:5:8fff:ff:ff:ff:ff
 
 [Route]
diff --git a/test/test-network/conf/25-route-via-ipv6.network b/test/test-network/conf/25-route-via-ipv6.network
new file mode 100644 (file)
index 0000000..a0ba93e
--- /dev/null
@@ -0,0 +1,14 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=2001:1234:5:8f63::1/128
+Address=149.10.124.58/28
+
+[Route]
+Destination=2001:1234:5:8fff:ff:ff:ff:ff/128
+
+[Route]
+Destination=149.10.124.66
+Gateway=2001:1234:5:8fff:ff:ff:ff:ff
index c962c3d8458c2df163e91990b712294bf28b7ac1..099331db5053c23acd393871e203722df8f59612 100644 (file)
@@ -3,6 +3,7 @@ Name=eni99np1
 
 [Network]
 Address=192.168.100.100/24
+IPv6AcceptRA=no
 
 [SR-IOV]
 VirtualFunction=0
index 7e6f6b33e01e929e44b60c9c86914ca9d25202cc..de43c16d118799396f9dc1feca8267148b678d23 100644 (file)
@@ -6,5 +6,5 @@ DHCP=ipv4
 IPv6AcceptRA=no
 
 [Route]
-Gateway=_dhcp
+Gateway=_dhcp4
 Destination=10.0.0.0/8
index ce708e7da9a609663717f68f734650780d9fd1b2..604a953b5811364b0bc8e647f2532b2e76017fcf 100644 (file)
@@ -5,5 +5,5 @@ Name=veth99
 DHCP=ipv6
 
 [Route]
-Gateway=_dhcp
+Gateway=_ipv6ra
 Destination=2001:1234:5:9fff:ff:ff:ff:ff/128
index 9de0e3147bc3539b4e97f954f3f3a18c8da203e8..aec1d1b2c312a6922f590d1e02cd71d402372709 100644 (file)
@@ -2,9 +2,9 @@
 Name=veth-peer
 
 [Network]
-IPv6PrefixDelegation=yes
+IPv6SendRA=yes
 
-[IPv6PrefixDelegation]
+[IPv6SendRA]
 DNS=_link_local 2002:da8:1:0::1
 DNSLifetimeSec=1min
 
index 9dc32cb4da016c544104d3b262d210ce60f59306..a0ac1e45379c7f854b0e0d9a9eaa7a30ecfcf5f8 100644 (file)
@@ -3,7 +3,7 @@ Name=veth99
 
 [Network]
 DHCP=no
-IPv6PrefixDelegation=yes
+IPv6SendRA=yes
 
 [IPv6Prefix]
 Prefix=2001:db8:0:1::/64
index 3e57b335ceeef1b25bddb1da68447c9f50cdfb5a..752b2fee435f0c8de327cc2e1e42e5412f2dc6d8 100755 (executable)
@@ -146,6 +146,20 @@ def expectedFailureIfNexthopIsNotAvailable():
 
     return f
 
+def expectedFailureIfRTA_VIAIsNotSupported():
+    def f(func):
+        call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
+        call('ip link set up dev dummy98', stderr=subprocess.DEVNULL)
+        call('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98', stderr=subprocess.DEVNULL)
+        rc = call('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98', stderr=subprocess.DEVNULL)
+        call('ip link del dummy98', stderr=subprocess.DEVNULL)
+        if rc == 0:
+            return func
+        else:
+            return unittest.expectedFailure(func)
+
+    return f
+
 def expectedFailureIfAlternativeNameIsNotAvailable():
     def f(func):
         call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
@@ -382,6 +396,9 @@ def remove_routing_policy_rule_tables(tables):
         rc = 0
         while rc == 0:
             rc = call('ip rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+        rc = 0
+        while rc == 0:
+            rc = call('ip -6 rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 
 def remove_routes(routes):
     for route_type, addr in routes:
@@ -745,6 +762,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     links = [
         '6rdtun99',
         'bareudp99',
+        'bond98',
         'bond99',
         'bridge99',
         'dropin-test',
@@ -870,6 +888,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         '25-sit-tunnel.netdev',
         '25-tap.netdev',
         '25-tun.netdev',
+        '25-tunnel-any-any.network',
         '25-tunnel-local-any.network',
         '25-tunnel-remote-any.network',
         '25-tunnel.network',
@@ -1723,6 +1742,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         '25-address-dad-veth-peer.network',
         '25-address-dad-veth99.network',
         '25-address-link-section.network',
+        '25-address-peer-ipv4.network',
         '25-address-preferred-lifetime-zero.network',
         '25-address-static.network',
         '25-bind-carrier.network',
@@ -1755,6 +1775,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         '25-prefix-route-without-vrf.network',
         '25-route-ipv6-src.network',
         '25-route-static.network',
+        '25-route-via-ipv6.network',
         '25-route-vrf.network',
         '25-gateway-static.network',
         '25-gateway-next-static.network',
@@ -1866,6 +1887,21 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         print(output)
         self.assertNotRegex(output, '192.168.100.10/24')
 
+    def test_address_peer_ipv4(self):
+        # test for issue #17304
+        copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
+
+        for trial in range(2):
+            if trial == 0:
+                start_networkd()
+            else:
+                restart_networkd()
+
+            self.wait_online(['dummy98:routable'])
+
+            output = check_output('ip -4 address show dev dummy98')
+            self.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output)
+
     @expectedFailureIfModuleIsNotAvailable('vrf')
     def test_prefix_route(self):
         copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
@@ -2125,10 +2161,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
         self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
 
-        print('### ip -6 route show dev dummy98 default')
-        output = check_output('ip -6 route show dev dummy98 default')
+        print('### ip -6 route show default')
+        output = check_output('ip -6 route show default')
         print(output)
-        self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
+        self.assertRegex(output, 'default')
+        self.assertRegex(output, 'via 2001:1234:5:8fff:ff:ff:ff:ff')
 
         print('### ip -4 route show dev dummy98')
         output = check_output('ip -4 route show dev dummy98')
@@ -2193,6 +2230,27 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
         self.assertRegex(output, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
 
+    @expectedFailureIfRTA_VIAIsNotSupported()
+    def test_route_via_ipv6(self):
+        copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
+        print(output)
+
+        print('### ip -6 route show dev dummy98')
+        output = check_output('ip -6 route show dev dummy98')
+        print(output)
+        self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
+        self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
+
+        print('### ip -4 route show dev dummy98')
+        output = check_output('ip -4 route show dev dummy98')
+        print(output)
+        self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
+        self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
+
     @expectedFailureIfModuleIsNotAvailable('vrf')
     def test_route_vrf(self):
         copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
@@ -2414,9 +2472,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         output = check_output('ip -4 route show dev dummy98')
         print(output)
         self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
-        output = check_output('ip -6 route show dev dummy98')
+        output = check_output('ip -6 route show default')
         print(output)
-        self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
+        self.assertRegex(output, 'default')
+        self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
 
         check_output('ip link del dummy98')
 
@@ -2437,9 +2496,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         output = check_output('ip -4 route show dev dummy98')
         print(output)
         self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
-        output = check_output('ip -6 route show dev dummy98')
+        output = check_output('ip -6 route show default')
         print(output)
-        self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
+        self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
 
     def test_bind_carrier(self):
         check_output('ip link add dummy98 type dummy')
@@ -3840,7 +3899,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
 
         output = check_output('ip route list dev veth99 10.0.0.0/8')
         print(output)
-        self.assertRegex(output, '10.0.0.0/8 via 192.168.5.1 proto static')
+        self.assertRegex(output, '10.0.0.0/8 via 192.168.5.1 proto dhcp')
 
     def test_dhcp_client_gateway_ipv6(self):
         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index fb465d76bbca5eed338988ecc969f57addbb1884..1246ec2ee73273b2fd38fe89d0fccbf13564a8fe 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test for Path units
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
index bcdafe4f3072967bb0c6d0eee853aef9e3fc3952..6a9bac09cdc274cd2a1ad7d92adcf5ed3793ab71 100644 (file)
@@ -2,6 +2,6 @@
 Description=Service Test Path Unit
 
 [Service]
-ExecStart=/bin/true
-Type=simple
+ExecStart=sleep infinity
+Type=exec
 RemainAfterExit=true
diff --git a/test/test-path/path-service.service b/test/test-path/path-service.service
deleted file mode 100644 (file)
index f8499ec..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Service Test for Path units
-
-[Service]
-ExecStart=/bin/true
-Type=oneshot
diff --git a/test/test-sysusers.sh.in b/test/test-sysusers.sh.in
new file mode 100755 (executable)
index 0000000..6e133cc
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+set -e
+
+SYSUSERS="${1:-systemd-sysusers}"
+
+[ -e "$(dirname $0)/../systemd-runtest.env" ] && . "$(dirname $0)/../systemd-runtest.env"
+SYSTEMD_TEST_DATA=${SYSTEMD_TEST_DATA:-@SYSTEMD_TEST_DATA@}
+SOURCE=$SYSTEMD_TEST_DATA/test-sysusers
+
+TESTDIR=$(mktemp --tmpdir --directory "test-sysusers.XXXXXXXXXX")
+trap "rm -rf '$TESTDIR'" EXIT INT QUIT PIPE
+
+prepare_testdir() {
+    mkdir -p $TESTDIR/etc/sysusers.d/
+    mkdir -p $TESTDIR/usr/lib/sysusers.d/
+    rm -f $TESTDIR/etc/*{passwd,group,shadow}
+    for i in $1.initial-{passwd,group,shadow}; do
+        test -f $i && cp $i $TESTDIR/etc/${i#*.initial-}
+    done
+    return 0
+}
+
+[ @SYSTEM_UID_MAX@ -lt @SYSTEM_GID_MAX@ ] && system_guid_max=@SYSTEM_UID_MAX@ || system_guid_max=@SYSTEM_GID_MAX@
+
+preprocess() {
+    m=${2:-$system_guid_max}
+
+    sed -e "s/SYSTEM_UGID_MAX/$m/g;
+            s#NOLOGIN#@NOLOGIN@#g" "$1"
+}
+
+compare() {
+    if ! diff -u $TESTDIR/etc/passwd <(preprocess $1.expected-passwd $3); then
+        echo "**** Unexpected output for $f $2"
+        exit 1
+    fi
+
+    if ! diff -u $TESTDIR/etc/group <(preprocess $1.expected-group $3); then
+        echo "**** Unexpected output for $f $2"
+        exit 1
+    fi
+}
+
+rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
+
+# happy tests
+for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
+    echo "*** Running $f"
+    prepare_testdir ${f%.input}
+    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
+    $SYSUSERS --root=$TESTDIR
+
+    compare ${f%.*} ""
+done
+
+for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
+    echo "*** Running $f on stdin"
+    prepare_testdir ${f%.input}
+    touch $TESTDIR/etc/sysusers.d/test.conf
+    cat $f | $SYSUSERS --root=$TESTDIR -
+
+    compare ${f%.*} "on stdin"
+done
+
+for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
+    echo "*** Running $f on stdin with --replace"
+    prepare_testdir ${f%.input}
+    touch $TESTDIR/etc/sysusers.d/test.conf
+    # this overrides test.conf which is masked on disk
+    cat $f | $SYSUSERS --root=$TESTDIR --replace=/etc/sysusers.d/test.conf -
+    # this should be ignored
+    cat $SOURCE/test-1.input | $SYSUSERS --root=$TESTDIR --replace=/usr/lib/sysusers.d/test.conf -
+
+    compare ${f%.*} "on stdin with --replace"
+done
+
+# test --inline
+echo "*** Testing --inline"
+prepare_testdir $SOURCE/inline
+# copy a random file to make sure it is ignored
+cp $f $TESTDIR/etc/sysusers.d/confuse.conf
+$SYSUSERS --root=$TESTDIR --inline \
+          "u     u1   222 -     - /bin/zsh" \
+          "g     g1   111"
+
+compare $SOURCE/inline "(--inline)"
+
+# test --replace
+echo "*** Testing --inline with --replace"
+prepare_testdir $SOURCE/inline
+# copy a random file to make sure it is ignored
+cp $f $TESTDIR/etc/sysusers.d/confuse.conf
+$SYSUSERS --root=$TESTDIR \
+          --inline \
+          --replace=/etc/sysusers.d/confuse.conf \
+          "u     u1   222 -     - /bin/zsh" \
+          "g     g1   111"
+
+compare $SOURCE/inline "(--inline --replace=…)"
+
+rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
+
+cat >$TESTDIR/etc/login.defs <<EOF
+SYS_UID_MIN abcd
+SYS_UID_MAX abcd
+SYS_GID_MIN abcd
+SYS_GID_MAX abcd
+SYS_UID_MIN 401
+SYS_UID_MAX 555
+SYS_GID_MIN 405
+SYS_GID_MAX 666
+SYS_UID_MIN abcd
+SYS_UID_MAX abcd
+SYS_GID_MIN abcd
+SYS_GID_MAX abcd
+SYS_UID_MIN999
+SYS_UID_MAX999
+SYS_GID_MIN999
+SYS_GID_MAX999
+EOF
+
+for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
+    echo "*** Running $f (with login.defs)"
+    prepare_testdir ${f%.input}
+    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
+    $SYSUSERS --root=$TESTDIR
+
+    [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
+    compare ${f%.*} "(with login.defs)" $bound
+done
+
+rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
+
+mv $TESTDIR/etc/login.defs $TESTDIR/etc/login.defs.moved
+ln -s ../../../../../etc/login.defs.moved $TESTDIR/etc/login.defs
+
+for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
+    echo "*** Running $f (with login.defs symlinked)"
+    prepare_testdir ${f%.input}
+    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
+    $SYSUSERS --root=$TESTDIR
+
+    [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
+    compare ${f%.*} "(with login.defs symlinked)" $bound
+done
+
+rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
+
+# tests for error conditions
+for f in $(ls -1 $SOURCE/unhappy-*.input | sort -V); do
+    echo "*** Running test $f"
+    prepare_testdir ${f%.input}
+    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
+    $SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/err
+    if ! diff -u $TESTDIR/err  ${f%.*}.expected-err; then
+        echo "**** Unexpected error output for $f"
+        cat $TESTDIR/err
+        exit 1
+    fi
+done
diff --git a/test/test-sysusers/test-10.expected-group b/test/test-sysusers/test-10.expected-group
new file mode 100644 (file)
index 0000000..c94a832
--- /dev/null
@@ -0,0 +1,2 @@
+u1:x:300:u2
+u2:x:SYSTEM_UGID_MAX:
diff --git a/test/test-sysusers/test-10.expected-passwd b/test/test-sysusers/test-10.expected-passwd
new file mode 100644 (file)
index 0000000..e5f2a69
--- /dev/null
@@ -0,0 +1,2 @@
+u1:x:300:300::/:NOLOGIN
+u2:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN
similarity index 66%
rename from test/TEST-21-SYSUSERS/test-13.expected-group
rename to test/test-sysusers/test-13.expected-group
index c78ea54bd30cad5ce3950793d137e369acf6bf09..1677d41b45b8cd90fbe93201d3e363dfbfb28dc3 100644 (file)
@@ -1,5 +1,5 @@
 hoge:x:300:
 baz:x:302:
-yyy:x:SYSTEM_GID_MAX:
+yyy:x:SYSTEM_UGID_MAX:
 foo:x:301:
 ccc:x:305:
similarity index 72%
rename from test/TEST-21-SYSUSERS/test-13.expected-passwd
rename to test/test-sysusers/test-13.expected-passwd
index ffc20a8193cc123b4890f93ce48bb26843a1482c..4a2c34b4cbe3c9bd145f5d11b28177ca0403b4af 100644 (file)
@@ -2,4 +2,4 @@ foo:x:301:301::/:NOLOGIN
 aaa:x:303:302::/:NOLOGIN
 bbb:x:304:302::/:NOLOGIN
 ccc:x:305:305::/:NOLOGIN
-zzz:x:306:SYSTEM_GID_MAX::/:NOLOGIN
+zzz:x:306:SYSTEM_UGID_MAX::/:NOLOGIN
diff --git a/test/test-sysusers/test-14.expected-passwd b/test/test-sysusers/test-14.expected-passwd
new file mode 100644 (file)
index 0000000..3c3bef2
--- /dev/null
@@ -0,0 +1 @@
+aaa:x:SYSTEM_UGID_MAX:987::/:NOLOGIN
similarity index 57%
rename from test/TEST-21-SYSUSERS/test-2.expected-group
rename to test/test-sysusers/test-2.expected-group
index 8fcc03f4e9fd36113ad6c8a53936a47410779dc4..fa216d79dec138367788438a014055e3a1912c20 100644 (file)
@@ -1,4 +1,4 @@
-u1:x:SYSTEM_UID_MAX:
+u1:x:SYSTEM_UGID_MAX:
 u2:x:777:
 u3:x:778:
 u4:x:779:
similarity index 61%
rename from test/TEST-21-SYSUSERS/test-2.expected-passwd
rename to test/test-sysusers/test-2.expected-passwd
index af8068813b6978fb820eca5a78a30a813724d900..ce49e84aad8041bb3b62e2ce4c15707bfbd4bda2 100644 (file)
@@ -1,4 +1,4 @@
-u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX:some gecos:/random/dir:NOLOGIN
+u1:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX:some gecos:/random/dir:NOLOGIN
 u2:x:777:777:some gecos:/random/dir:/bin/zsh
 u3:x:778:778::/random/dir2:/bin/bash
 u4:x:779:779::/:/bin/csh
similarity index 81%
rename from test/TEST-21-SYSUSERS/test-2.input
rename to test/test-sysusers/test-2.input
index cedea9e401946b0a7358144e960e7dc4aa013412..773d9e5da1268b304331ebb75c85fb3eff7f2381 100644 (file)
@@ -1,4 +1,4 @@
-# Test generation of ID dynamically based on SYSTEM_UID_MAX and
+# Test generation of ID dynamically based on SYSTEM_UGID_MAX and
 # replacement of all fields up to the login shell.
 #
 #Type Name ID  GECOS        homedir      shell
diff --git a/test/test-sysusers/test-6.expected-group b/test/test-sysusers/test-6.expected-group
new file mode 100644 (file)
index 0000000..2ef661a
--- /dev/null
@@ -0,0 +1,2 @@
+g1:x:111:
+u1:x:SYSTEM_UGID_MAX:
diff --git a/test/test-sysusers/test-6.expected-passwd b/test/test-sysusers/test-6.expected-passwd
new file mode 100644 (file)
index 0000000..d589e2e
--- /dev/null
@@ -0,0 +1 @@
+u1:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN
diff --git a/test/test-sysusers/test-8.expected-passwd b/test/test-sysusers/test-8.expected-passwd
new file mode 100644 (file)
index 0000000..b5b8fac
--- /dev/null
@@ -0,0 +1 @@
+username:x:SYSTEM_UGID_MAX:300::/:NOLOGIN
diff --git a/test/test-sysusers/test-9.expected-passwd b/test/test-sysusers/test-9.expected-passwd
new file mode 100644 (file)
index 0000000..fc2a060
--- /dev/null
@@ -0,0 +1,2 @@
+user1:x:300:300::/:NOLOGIN
+user2:x:SYSTEM_UGID_MAX:300::/:NOLOGIN
index a0dc095688685cb44f2452b9228b151d1389af59..278145285c1caa703e31947e06322ffa469ca70a 100644 (file)
@@ -2,5 +2,5 @@
 Description=ForeverPrintHola service
 
 [Service]
-Type=simple
+Type=exec
 ExecStart=sh -x -c 'while :; do printf "Hola\n" || touch /i-lose-my-logs; sleep 1; done'
index 9264f151f31b9d1849eddd318bbc5d1e3a4630f6..6832cb241c4eb283c30ea9bfe290783cc5bcb8df 100644 (file)
@@ -4,6 +4,6 @@ StartLimitIntervalSec=1m
 StartLimitBurst=3
 
 [Service]
-Type=simple
+Type=exec
 ExecStart=false
 Restart=always
index b44baad91a650134b8b5a825c8fdf900d55d8792..34e89ff7527af75af70cc45fa250582b534284bb 100644 (file)
@@ -13,7 +13,7 @@ StopWhenUnneeded=yes
 
 [Service]
 ExecStartPre=rm -f /failed /testok
-Type=simple
+Type=exec
 TimeoutStartSec=infinity
 ExecStartPre=/usr/lib/systemd/tests/testdata/units/%N.sh
 ExecStart=true
index 5abdb53eb31cdba5f8b3a7e8bc0ee53067d335fd..5c625568953bb88b18280d854afa79349772197d 100755 (executable)
@@ -38,6 +38,22 @@ STATE=$(systemctl show --property=ActiveState --value sys-devices-virtual-net-lo
 rm -f /run/udev/rules.d/50-testsuite.rules
 udevadm control --reload --timeout=600
 
+# test for issue #16967
+
+ip link add hoge type dummy
+udevadm info --wait-for-initialization=10s /sys/devices/virtual/net/hoge
+sleep 1
+if ! systemctl status sys-devices-virtual-net-hoge.device; then exit 1; fi
+if ! systemctl status sys-subsystem-net-devices-hoge.device; then exit 1; fi
+
+ip link set hoge name foobar
+udevadm info --wait-for-initialization=10s /sys/devices/virtual/net/foobar
+sleep 1
+if systemctl status sys-devices-virtual-net-hoge.device; then exit 1; fi
+if systemctl status sys-subsystem-net-devices-hoge.device; then exit 1; fi
+if ! systemctl status sys-devices-virtual-net-foobar.device; then exit 1; fi
+if ! systemctl status sys-subsystem-net-devices-foobar.device; then exit 1; fi
+
 echo OK > /testok
 
 exit 0
index d6e1a3557a3600dc892cb8d15f3f3a8893fe79da..d615ac2ea7e5d636e36cbe4553aaf608f30ef8ad 100755 (executable)
@@ -60,11 +60,12 @@ fi
 umount ${image_dir}/mount
 umount ${image_dir}/mount2
 
-systemd-run -t --property RootImage=${image}.raw /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p RootImage=${image}.raw cat /usr/lib/os-release | grep -q -F "MARKER=1"
 mv ${image}.verity ${image}.fooverity
 mv ${image}.roothash ${image}.foohash
-systemd-run -t --property RootImage=${image}.raw --property RootHash=${image}.foohash --property RootVerity=${image}.fooverity /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property RootImage=${image}.raw --property RootHash=${roothash} --property RootVerity=${image}.fooverity /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p RootImage=${image}.raw -p RootHash=${image}.foohash -p RootVerity=${image}.fooverity cat /usr/lib/os-release | grep -q -F "MARKER=1"
+# Let's use the long option name just here as a test
+systemd-run -t --property RootImage=${image}.raw --property RootHash=${roothash} --property RootVerity=${image}.fooverity cat /usr/lib/os-release | grep -q -F "MARKER=1"
 mv ${image}.fooverity ${image}.verity
 mv ${image}.foohash ${image}.roothash
 
@@ -73,18 +74,27 @@ machine="$(uname -m)"
 if [ "${machine}" = "x86_64" ]; then
     root_guid=4f68bce3-e8cd-4db1-96e7-fbcaf984b709
     verity_guid=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5
+    architecture="x86-64"
 elif [ "${machine}" = "i386" ] || [ "${machine}" = "i686" ] || [ "${machine}" = "x86" ]; then
     root_guid=44479540-f297-41b2-9af7-d131d5f0458a
     verity_guid=d13c5d3b-b5d1-422a-b29f-9454fdc89d76
+    architecture="x86"
 elif [ "${machine}" = "aarch64" ] || [ "${machine}" = "aarch64_be" ] || [ "${machine}" = "armv8b" ] || [ "${machine}" = "armv8l" ]; then
     root_guid=b921b045-1df0-41c3-af44-4c6f280d3fae
     verity_guid=df3300ce-d69f-4c92-978c-9bfb0f38d820
+    architecture="arm64"
 elif [ "${machine}" = "arm" ]; then
     root_guid=69dad710-2ce4-4e3c-b16c-21a1d49abed3
     verity_guid=7386cdf2-203c-47a9-a498-f2ecce45a2d6
+    architecture="arm"
 elif [ "${machine}" = "ia64" ]; then
     root_guid=993d8d3d-f80e-4225-855a-9daf8ed7ea97
     verity_guid=86ed10d5-b607-45bb-8957-d350f23d0571
+    architecture="ia64"
+elif [ "${machine}" = "ppc64le" ]; then
+    # There's no support of PPC in the discoverable partitions specification yet, so skip the rest for now
+    echo OK >/testok
+    exit 0
 else
     echo "Unexpected uname -m: ${machine} in testsuite-50.sh, please fix me"
     exit 1
@@ -101,7 +111,7 @@ if [ ${root_size} -ge 1024 ]; then
 else
     root_size="${root_size}KiB"
 fi
-verity_size="${verity_size}KiB"
+verity_size="$((${verity_size} * 2))KiB"
 uuid="$(head -c 32 ${image}.roothash | cut -c -8)-$(head -c 32 ${image}.roothash | cut -c 9-12)-$(head -c 32 ${image}.roothash | cut -c 13-16)-$(head -c 32 ${image}.roothash | cut -c 17-20)-$(head -c 32 ${image}.roothash | cut -c 21-)"
 echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk ${image}.gpt
 uuid="$(tail -c 32 ${image}.roothash | cut -c -8)-$(tail -c 32 ${image}.roothash | cut -c 9-12)-$(tail -c 32 ${image}.roothash | cut -c 13-16)-$(tail -c 32 ${image}.roothash | cut -c 17-20)-$(tail -c 32 ${image}.roothash | cut -c 21-)"
@@ -117,8 +127,8 @@ losetup -d ${loop}
 ROOT_UUID=$(systemd-id128 -u show $(head -c 32 ${image}.roothash) -u | tail -n 1 | cut -b 6-)
 VERITY_UUID=$(systemd-id128 -u show $(tail -c 32 ${image}.roothash) -u | tail -n 1 | cut -b 6-)
 
-systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'$ROOT_UUID'","fstype":"squashfs","architecture":"x86-64","verity":"yes","node":'
-systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'$VERITY_UUID'","fstype":"DM_verity_hash","architecture":"x86-64","verity":null,"node":'
+systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'$ROOT_UUID'","fstype":"squashfs","architecture":"'$architecture'","verity":"yes","node":'
+systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'$VERITY_UUID'","fstype":"DM_verity_hash","architecture":"'$architecture'","verity":null,"node":'
 systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F "MARKER=1"
 systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F -f $os_release
 
@@ -128,19 +138,19 @@ cat ${image_dir}/mount/etc/os-release | grep -q -F -f $os_release
 cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1"
 umount ${image_dir}/mount
 
-systemd-run -t --property RootImage=${image}.gpt --property RootHash=${roothash} /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+# add explicit -p MountAPIVFS=yes once to test the parser
+systemd-run -t -p RootImage=${image}.gpt -p RootHash=${roothash} -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
 
-systemd-run -t --property RootImage=${image}.raw --property RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
-systemd-run -t --property RootImage=${image}.gpt --property RootImageOptions="root:ro,noatime root:ro,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "noatime"
+systemd-run -t -p RootImage=${image}.raw -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" mount | grep -F "squashfs" | grep -q -F "nosuid"
+systemd-run -t -p RootImage=${image}.gpt -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime"
 
 mkdir -p mkdir -p ${image_dir}/result
-cat > /run/systemd/system/testservice-50a.service <<EOF
+cat >/run/systemd/system/testservice-50a.service <<EOF
 [Service]
 Type=oneshot
-ExecStart=bash -c "mount > /run/result/a"
+ExecStart=bash -c "mount >/run/result/a"
 BindPaths=${image_dir}/result:/run/result
 TemporaryFileSystem=/run
-MountAPIVFS=yes
 RootImage=${image}.raw
 RootImageOptions=root:ro,noatime home:ro,dev relatime,dev
 RootImageOptions=nosuid,dev
@@ -149,33 +159,34 @@ systemctl start testservice-50a.service
 grep -F "squashfs" ${image_dir}/result/a | grep -q -F "noatime"
 grep -F "squashfs" ${image_dir}/result/a | grep -q -F -v "nosuid"
 
-cat > /run/systemd/system/testservice-50b.service <<EOF
+cat >/run/systemd/system/testservice-50b.service <<EOF
 [Service]
 Type=oneshot
-ExecStart=bash -c "mount > /run/result/b"
+ExecStart=bash -c "mount >/run/result/b"
 BindPaths=${image_dir}/result:/run/result
 TemporaryFileSystem=/run
-MountAPIVFS=yes
 RootImage=${image}.gpt
 RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev
 RootImageOptions=home:ro,dev nosuid,dev,%%foo
+# this is the default, but let's specify once to test the parser
+MountAPIVFS=yes
 EOF
 systemctl start testservice-50b.service
 grep -F "squashfs" ${image_dir}/result/b | grep -q -F "noatime"
 
-# Check that specifier escape is applied %%foo -> %foo
+# Check that specifier escape is applied %%foo  %foo
 busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
 
 # Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image
-systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nosuid,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
-systemd-run -t --property MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
-systemd-run -t --property MountImages="${image}.raw:/run/img2\:3" /usr/bin/cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property MountImages="${image}.raw:/run/img2\:3:nosuid" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
-systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
-systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.gpt --property RootHash=${roothash} --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nosuid,dev" mount | grep -F "squashfs" | grep -q -F "nosuid"
+systemd-run -t -p MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" mount | grep -F "squashfs" | grep -q -F "nosuid"
+systemd-run -t -p MountImages="${image}.raw:/run/img2\:3" cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p MountImages="${image}.raw:/run/img2\:3:nosuid" mount | grep -F "squashfs" | grep -q -F "nosuid"
+systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.raw -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.raw -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.gpt -p RootHash=${roothash} -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
 cat >/run/systemd/system/testservice-50c.service <<EOF
 [Service]
 MountAPIVFS=yes
@@ -183,9 +194,9 @@ TemporaryFileSystem=/run
 RootImage=${image}.raw
 MountImages=${image}.gpt:/run/img1:root:noatime:home:relatime
 MountImages=${image}.raw:/run/img2\:3:nosuid
-ExecStart=bash -c "cat /run/img1/usr/lib/os-release > /run/result/c"
-ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >> /run/result/c"
-ExecStart=bash -c "mount >> /run/result/c"
+ExecStart=bash -c "cat /run/img1/usr/lib/os-release >/run/result/c"
+ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c"
+ExecStart=bash -c "mount >>/run/result/c"
 BindPaths=${image_dir}/result:/run/result
 Type=oneshot
 EOF
@@ -194,6 +205,6 @@ grep -q -F "MARKER=1" ${image_dir}/result/c
 grep -F "squashfs" ${image_dir}/result/c | grep -q -F "noatime"
 grep -F "squashfs" ${image_dir}/result/c | grep -q -F -v "nosuid"
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 8b6a1dafc322709b4d022e6a2f7345240010375a..e8e9ed48ae33c3717ffeafa65ebed87bad900287 100644 (file)
 # control writes into pstore.
 #
 # The crash_kexec_post_notifiers parameter enables the kernel to write
-# dmesg (including stack trace) into pstore upon a panic, and
-# printk.always_kmsg_dump parameter enables the kernel to write dmesg
+# dmesg (including stack trace) into pstore upon a panic even if kdump
+# is loaded, only needed if you want to use pstore with kdump. Without
+# this parameter, kdump could block writing to pstore for stability
+# reason. Note this increases the risk of kdump failure even if pstore
+# is not available.
+#
+# The printk.always_kmsg_dump parameter enables the kernel to write dmesg
 # upon a normal shutdown (shutdown, reboot, halt).
 #
 # To configure the kernel parameters, uncomment the appropriate
@@ -26,4 +31,4 @@
 
 d /var/lib/systemd/pstore 0755 root root 14d
 #w- /sys/module/printk/parameters/always_kmsg_dump - - - - Y
-w- /sys/module/kernel/parameters/crash_kexec_post_notifiers - - - - Y
+#w- /sys/module/kernel/parameters/crash_kexec_post_notifiers - - - - Y
index 41e6cc95862bef8b68b0538675f87e91ac273ec6..b6367f3c3ef12b1bb431bd66f7c8d78fbadbe910 100644 (file)
@@ -226,6 +226,8 @@ PCI_IDS += [
     '8086:02a4',
     # USB controller
     '8086:02ed',
+    # Volteer xHCI controller
+    '8086:a0ed',
     # Graphics
     '8086:9b41',
     # DSP
index a20edc0f341d673534c828d03f732f4b2dff5469..8114522a1c45240ebe47f9abe2d2677c5953cf53 100755 (executable)
@@ -7,18 +7,18 @@
 
 import chromiumos.gen_autosuspend_rules
 
-print('# pci:v<00VENDOR>d<00DEVICE> (8 uppercase hexadecimal digits twice)')
+print('# pci:v<00VENDOR>d<00DEVICE>:* (8 uppercase hexadecimal digits twice)')
 for entry in chromiumos.gen_autosuspend_rules.PCI_IDS:
     vendor, device = entry.split(':')
     vendor = int(vendor, 16)
     device = int(device, 16)
-    print('pci:v{:08X}d{:08X}*'.format(vendor, device))
+    print('pci:v{:08X}d{:08X}:*'.format(vendor, device))
 
-print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice)')
+print('# usb:v<VEND>p<PROD>:* (4 uppercase hexadecimal digits twice)')
 for entry in chromiumos.gen_autosuspend_rules.USB_IDS:
     vendor, product = entry.split(':')
     vendor = int(vendor, 16)
     product = int(product, 16)
-    print('usb:v{:04X}p{:04X}*'.format(vendor, product))
+    print('usb:v{:04X}p{:04X}:*'.format(vendor, product))
 
 print(' ID_AUTOSUSPEND=1')
diff --git a/units/first-boot-complete.target b/units/first-boot-complete.target
new file mode 100644 (file)
index 0000000..98b236e
--- /dev/null
@@ -0,0 +1,14 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=First Boot Complete
+Documentation=man:systemd.special(7)
+RefuseManualStart=yes
+ConditionFirstBoot=yes
diff --git a/units/initrd-cryptsetup.target b/units/initrd-cryptsetup.target
new file mode 100644 (file)
index 0000000..2a2938c
--- /dev/null
@@ -0,0 +1,17 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Initrd Encrypted Volumes
+Documentation=man:systemd.special(7)
+OnFailure=emergency.target
+OnFailureJobMode=replace-irreversibly
+AssertPathExists=/etc/initrd-release
+DefaultDependencies=no
+Conflicts=shutdown.target
index 275daad3f4e8609d1c253590d7fd3ca544e2d9bf..a55e71786888525566770968b58e8c2688e3c4c2 100644 (file)
@@ -17,6 +17,7 @@ units = [
         ['emergency.target',                    ''],
         ['exit.target',                         ''],
         ['final.target',                        ''],
+        ['first-boot-complete.target',          ''],
         ['getty.target',                        '',
          'multi-user.target.wants/'],
         ['getty-pre.target',                    ''],
@@ -27,6 +28,8 @@ units = [
         ['hybrid-sleep.target',                 'ENABLE_HIBERNATE'],
         ['suspend-then-hibernate.target',       'ENABLE_HIBERNATE'],
         ['initrd-cleanup.service',              'ENABLE_INITRD'],
+        ['initrd-cryptsetup.target',            'HAVE_LIBCRYPTSETUP ENABLE_INITRD',
+         'sysinit.target.wants/'],
         ['initrd-fs.target',                    'ENABLE_INITRD'],
         ['initrd-parse-etc.service',            'ENABLE_INITRD'],
         ['initrd-root-device.target',           'ENABLE_INITRD'],
@@ -102,6 +105,7 @@ units = [
         ['systemd-firstboot.service',           'ENABLE_FIRSTBOOT',
          'sysinit.target.wants/'],
         ['systemd-halt.service',                ''],
+        ['systemd-homed-activate.service',      'ENABLE_HOMED'],
         ['systemd-initctl.socket',              'HAVE_SYSV_COMPAT',
          'sockets.target.wants/'],
         ['systemd-journal-catalog-update.service', '',
@@ -200,6 +204,7 @@ in_units = [
         ['systemd-networkd.service',             'ENABLE_NETWORKD'],
         ['systemd-networkd-wait-online.service', 'ENABLE_NETWORKD'],
         ['systemd-nspawn@.service',              ''],
+        ['systemd-oomd.service',                 'ENABLE_OOMD'],
         ['systemd-portabled.service',            'ENABLE_PORTABLED',
          'dbus-org.freedesktop.portable1.service'],
         ['systemd-userdbd.service',              'ENABLE_USERDB'],
index cab89fb42688536c0a766f9f4a04aa6aa6094b70..4b72bef84e24afbe80622b79cb008ce71c098896 100644 (file)
@@ -33,7 +33,7 @@ Before=rescue.service
 # The '-o' option value tells agetty to replace 'login' arguments with an
 # option to preserve environment (-p), followed by '--' for safety, and then
 # the entered username.
-ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,38400,9600 %I $TERM
+ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,57600,38400,9600 %I $TERM
 Type=idle
 Restart=always
 UtmpIdentifier=%I
index 9f5c7101cd50d846e0978a895245b74599383231..e17fef7b36eacdfb3da33d091ecd6a969efa1545 100644 (file)
@@ -13,7 +13,8 @@ Documentation=man:systemd-firstboot(1)
 DefaultDependencies=no
 Conflicts=shutdown.target
 After=systemd-remount-fs.service
-Before=systemd-sysusers.service sysinit.target shutdown.target
+Before=systemd-sysusers.service sysinit.target first-boot-complete.target shutdown.target
+Wants=first-boot-complete.target
 ConditionPathIsReadWrite=/etc
 ConditionFirstBoot=yes
 
diff --git a/units/systemd-homed-activate.service b/units/systemd-homed-activate.service
new file mode 100644 (file)
index 0000000..3a5057d
--- /dev/null
@@ -0,0 +1,23 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Home Area Activation
+Documentation=man:systemd-homed.service(8)
+After=home.mount systemd-homed.service
+Before=systemd-user-sessions.service
+
+[Service]
+ExecStop=homectl deactivate-all
+RemainAfterExit=true
+Type=oneshot
+
+[Install]
+WantedBy=systemd-homed.service
+Also=systemd-homed.service
index 7109e0351ced2d83188ae4c0c8afdd34b28b276d..4b6a91c9846e130a3fcf01b06479e41346ebc396 100644 (file)
@@ -10,6 +10,8 @@
 [Unit]
 Description=Home Area Manager
 Documentation=man:systemd-homed.service(8)
+Documentation=man:org.freedesktop.home1(5)
+
 After=home.mount
 
 [Service]
@@ -37,4 +39,4 @@ SystemCallFilter=@system-service @mount
 [Install]
 WantedBy=multi-user.target
 Alias=dbus-org.freedesktop.home1.service
-Also=systemd-userdbd.service
+Also=systemd-homed-activate.service systemd-userdbd.service
index 923f32f6dbb8802df8fd96f6070937f5539fd152..017441f9dadfb825a7538417478b1e1f70112ba1 100644 (file)
@@ -9,8 +9,10 @@
 
 [Unit]
 Description=Hostname Service
-Documentation=man:systemd-hostnamed.service(8) man:hostname(5) man:machine-info(5)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/hostnamed
+Documentation=man:systemd-hostnamed.service(8)
+Documentation=man:hostname(5)
+Documentation=man:machine-info(5)
+Documentation=man:org.freedesktop.resolve1(5)
 
 [Service]
 BusName=org.freedesktop.hostname1
index 1a6fae4b69daab0956828fa2298e564f5f9503ee..58a7b472599078568eafcee8c745251a24cdd7c2 100644 (file)
@@ -10,7 +10,7 @@
 [Unit]
 Description=Virtual Machine and Container Download Service
 Documentation=man:systemd-importd.service(8)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/importd
+Documentation=man:org.freedesktop.import1(5)
 
 [Service]
 ExecStart=@rootlibexecdir@/systemd-importd
index 69d25f67333095407be9b4c0392ff8db92156b72..47f147956b604db149e2cdc82b101baa8d6237fd 100644 (file)
@@ -9,8 +9,10 @@
 
 [Unit]
 Description=Locale Service
-Documentation=man:systemd-localed.service(8) man:locale.conf(5) man:vconsole.conf(5)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/localed
+Documentation=man:systemd-localed.service(8)
+Documentation=man:locale.conf(5)
+Documentation=man:vconsole.conf(5)
+Documentation=man:org.freedesktop.locale1(5)
 
 [Service]
 BusName=org.freedesktop.locale1
index ba1b9b791bc6985d7ad1d94ca748494809430fbc..cb44ccbae663c3172831fba891e46d97806844f7 100644 (file)
@@ -9,9 +9,11 @@
 
 [Unit]
 Description=User Login Management
-Documentation=man:systemd-logind.service(8) man:logind.conf(5)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/logind
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/multiseat
+Documentation=man:sd-login(3)
+Documentation=man:systemd-logind.service(8)
+Documentation=man:logind.conf(5)
+Documentation=man:org.freedesktop.login1(5)
+
 Wants=user.slice modprobe@drm.service
 After=nss-user-lookup.target user.slice modprobe@drm.service
 
index e3acb0f3260bc30ae28d6556296c561fe145c7ec..5616a3570192670176ffa74239ef2110ebd6b235 100644 (file)
@@ -12,8 +12,8 @@ Description=Commit a transient machine-id on disk
 Documentation=man:systemd-machine-id-commit.service(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-Before=sysinit.target shutdown.target
-After=local-fs.target
+Before=shutdown.target
+After=local-fs.target first-boot-complete.target
 ConditionPathIsReadWrite=/etc
 ConditionPathIsMountPoint=/etc/machine-id
 
index 3db0281f81dcb5f8589f5cd2c49b3cc4b93c6bc9..0e452ddcab1886539927823a3072d288227e710e 100644 (file)
@@ -10,7 +10,8 @@
 [Unit]
 Description=Virtual Machine and Container Registration Service
 Documentation=man:systemd-machined.service(8)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/machined
+Documentation=man:org.freedesktop.machine1(5)
+
 Wants=machine.slice
 After=machine.slice
 RequiresMountsFor=/var/lib/machines
diff --git a/units/systemd-oomd.service.in b/units/systemd-oomd.service.in
new file mode 100644 (file)
index 0000000..67bd117
--- /dev/null
@@ -0,0 +1,54 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Userspace Out-Of-Memory (OOM) Killer
+Documentation=man:systemd-oomd.service(8)
+DefaultDependencies=no
+Before=multi-user.target shutdown.target
+Conflicts=shutdown.target
+
+[Service]
+AmbientCapabilities=CAP_KILL CAP_DAC_OVERRIDE
+BusName=org.freedesktop.oom1
+CapabilityBoundingSet=CAP_KILL CAP_DAC_OVERRIDE
+ExecStart=@rootlibexecdir@/systemd-oomd
+IPAddressDeny=any
+LockPersonality=yes
+MemoryDenyWriteExecute=yes
+# Reserve some minimum amount of memory so that systemd-oomd can continue to
+# run in resource starved scenarios.
+MemoryMin=64M
+MemoryLow=64M
+NoNewPrivileges=yes
+OOMScoreAdjust=-900
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectClock=yes
+ProtectHome=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+ProtectSystem=strict
+Restart=on-failure
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+SystemCallArchitectures=native
+SystemCallErrorNumber=EPERM
+SystemCallFilter=@system-service
+Type=notify
+User=systemd-oom
+@SERVICE_WATCHDOG@
+
+[Install]
+WantedBy=multi-user.target
+Alias=dbus-org.freedesktop.oom1.service
index f97f99a966aa6edec4316438313d6893ce1dbf62..aa4b3e7357c2326911f1946c513d773a299542cd 100644 (file)
@@ -14,7 +14,8 @@ DefaultDependencies=no
 RequiresMountsFor=@RANDOM_SEED@
 Conflicts=shutdown.target
 After=systemd-remount-fs.service
-Before=shutdown.target
+Before=first-boot-complete.target shutdown.target
+Wants=first-boot-complete.target
 ConditionVirtualization=!container
 
 [Service]
index 2432485e9ee609866e6623187828293b800e8761..513d96b74cfa356a1dc9880fddab45bd1f0b0e59 100644 (file)
 [Unit]
 Description=Network Name Resolution
 Documentation=man:systemd-resolved.service(8)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/resolved
+Documentation=man:org.freedesktop.resolve1(5)
 Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
 Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
+
 DefaultDependencies=no
 After=systemd-sysusers.service systemd-networkd.service
 Before=network.target nss-lookup.target shutdown.target
index 2d51c0f8934482ac17b9056b9a1578f973c73a4f..f84bd3830b7365f7617b9235df5c3f498c44f787 100644 (file)
@@ -9,8 +9,9 @@
 
 [Unit]
 Description=Time & Date Service
-Documentation=man:systemd-timedated.service(8) man:localtime(5)
-Documentation=https://www.freedesktop.org/wiki/Software/systemd/timedated
+Documentation=man:systemd-timedated.service(8)
+Documentation=man:localtime(5)
+Documentation=man:org.freedesktop.timedate1(5)
 
 [Service]
 BusName=org.freedesktop.timedate1