summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze.c10
-rw-r--r--src/basic/af-list.c6
-rw-r--r--src/basic/arphrd-list.c4
-rw-r--r--src/basic/async.c4
-rw-r--r--src/basic/audit-util.h2
-rw-r--r--src/basic/bitmap.h2
-rw-r--r--src/basic/btrfs-util.c49
-rw-r--r--src/basic/btrfs-util.h4
-rw-r--r--src/basic/calendarspec.c238
-rw-r--r--src/basic/calendarspec.h3
-rw-r--r--src/basic/cap-list.c2
-rw-r--r--src/basic/cgroup-util.h6
-rw-r--r--src/basic/errno-list.c4
-rw-r--r--src/basic/escape.c16
-rw-r--r--src/basic/escape.h3
-rw-r--r--src/basic/exit-status.c4
-rw-r--r--src/basic/fd-util.h6
-rw-r--r--src/basic/fdset.c6
-rw-r--r--src/basic/fileio-label.c4
-rw-r--r--src/basic/fileio-label.h1
-rw-r--r--src/basic/fs-util.h2
-rw-r--r--src/basic/gunicode.h2
-rw-r--r--src/basic/hashmap.c2
-rw-r--r--src/basic/hostname-util.c2
-rw-r--r--src/basic/in-addr-util.c15
-rw-r--r--src/basic/in-addr-util.h1
-rw-r--r--src/basic/ioprio.h2
-rw-r--r--src/basic/json.c2
-rw-r--r--src/basic/json.h1
-rw-r--r--src/basic/label.c2
-rw-r--r--src/basic/lockfile-util.c8
-rw-r--r--src/basic/login-util.c2
-rw-r--r--src/basic/memfd-util.h2
-rw-r--r--src/basic/mempool.c2
-rw-r--r--src/basic/mkdir-label.c2
-rw-r--r--src/basic/mkdir.c2
-rw-r--r--src/basic/ordered-set.h11
-rw-r--r--src/basic/parse-util.c36
-rw-r--r--src/basic/parse-util.h2
-rw-r--r--src/basic/process-util.h6
-rw-r--r--src/basic/selinux-util.c6
-rw-r--r--src/basic/selinux-util.h2
-rw-r--r--src/basic/set.h1
-rw-r--r--src/basic/sigbus.c2
-rw-r--r--src/basic/siphash24.c112
-rw-r--r--src/basic/siphash24.h16
-rw-r--r--src/basic/socket-util.h4
-rw-r--r--src/basic/stat-util.h5
-rw-r--r--src/basic/strv.c2
-rw-r--r--src/basic/strxcpyx.c1
-rw-r--r--src/basic/terminal-util.h2
-rw-r--r--src/basic/time-util.c93
-rw-r--r--src/basic/unaligned.h47
-rw-r--r--src/basic/user-util.c2
-rw-r--r--src/basic/user-util.h2
-rw-r--r--src/basic/utf8.c4
-rw-r--r--src/basic/util.c12
-rw-r--r--src/basic/virt.c13
-rw-r--r--src/boot/efi/boot.c6
-rw-r--r--src/boot/efi/console.c2
-rw-r--r--src/boot/efi/graphics.c2
-rw-r--r--src/boot/efi/linux.c2
-rw-r--r--src/boot/efi/pefile.c2
-rw-r--r--src/boot/efi/splash.c2
-rw-r--r--src/boot/efi/stub.c6
-rw-r--r--src/bootchart/bootchart.h1
-rw-r--r--src/bootchart/store.h1
-rw-r--r--src/bootchart/svg.c14
-rw-r--r--src/bus-proxyd/bus-xml-policy.c14
-rw-r--r--src/bus-proxyd/bus-xml-policy.h2
-rw-r--r--src/bus-proxyd/driver.h1
-rw-r--r--src/bus-proxyd/stdio-bridge.c2
-rw-r--r--src/core/.gitignore1
-rw-r--r--src/core/audit-fd.c5
-rw-r--r--src/core/bus-endpoint.h2
-rw-r--r--src/core/bus-policy.h2
-rw-r--r--src/core/cgroup.c24
-rw-r--r--src/core/cgroup.h2
-rw-r--r--src/core/dbus-automount.c2
-rw-r--r--src/core/dbus-busname.c2
-rw-r--r--src/core/dbus-device.c4
-rw-r--r--src/core/dbus-kill.c5
-rw-r--r--src/core/dbus-kill.h2
-rw-r--r--src/core/dbus-manager.c43
-rw-r--r--src/core/dbus-mount.c2
-rw-r--r--src/core/dbus-path.c2
-rw-r--r--src/core/dbus-scope.h1
-rw-r--r--src/core/dbus-service.h1
-rw-r--r--src/core/dbus-slice.c4
-rw-r--r--src/core/dbus-slice.h1
-rw-r--r--src/core/dbus-socket.c1
-rw-r--r--src/core/dbus-socket.h1
-rw-r--r--src/core/dbus-swap.c2
-rw-r--r--src/core/dbus-swap.h1
-rw-r--r--src/core/dbus-target.c2
-rw-r--r--src/core/dbus-timer.c34
-rw-r--r--src/core/dbus-timer.h1
-rw-r--r--src/core/dbus-unit.h1
-rw-r--r--src/core/execute.c4
-rw-r--r--src/core/execute.h10
-rw-r--r--src/core/hostname-setup.c2
-rw-r--r--src/core/ima-setup.c2
-rw-r--r--src/core/job.c73
-rw-r--r--src/core/job.h1
-rw-r--r--src/core/kmod-setup.c6
-rw-r--r--src/core/load-dropin.c6
-rw-r--r--src/core/load-dropin.h2
-rw-r--r--src/core/load-fragment-gperf.gperf.m45
-rw-r--r--src/core/load-fragment.c306
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/locale-setup.c2
-rw-r--r--src/core/macros.systemd.in14
-rw-r--r--src/core/main.c11
-rw-r--r--src/core/manager.c2
-rw-r--r--src/core/manager.h4
-rw-r--r--src/core/mount-setup.c4
-rw-r--r--src/core/mount.h2
-rw-r--r--src/core/scope.c14
-rw-r--r--src/core/selinux-access.c4
-rw-r--r--src/core/selinux-access.h1
-rw-r--r--src/core/selinux-setup.c2
-rw-r--r--src/core/service.h4
-rw-r--r--src/core/slice.c3
-rw-r--r--src/core/socket.c13
-rw-r--r--src/core/socket.h4
-rw-r--r--src/core/swap.c8
-rw-r--r--src/core/system.conf3
-rw-r--r--src/core/timer.c75
-rw-r--r--src/core/timer.h2
-rw-r--r--src/core/transaction.c2
-rw-r--r--src/core/transaction.h6
-rw-r--r--src/core/triggers.systemd.in64
-rw-r--r--src/core/unit.c61
-rw-r--r--src/core/unit.h21
-rw-r--r--src/firstboot/firstboot.c2
-rw-r--r--src/fsck/fsck.c8
-rw-r--r--src/fstab-generator/fstab-generator.c10
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c4
-rw-r--r--src/hibernate-resume/hibernate-resume.c2
-rw-r--r--src/hostname/hostnamed.c2
-rw-r--r--src/import/aufs-util.c2
-rw-r--r--src/import/curl-util.c18
-rw-r--r--src/import/curl-util.h2
-rw-r--r--src/import/export-raw.c4
-rw-r--r--src/import/export-raw.h3
-rw-r--r--src/import/export-tar.h3
-rw-r--r--src/import/import-compress.h5
-rw-r--r--src/import/import-raw.h3
-rw-r--r--src/import/import-tar.h3
-rw-r--r--src/import/pull-common.c2
-rw-r--r--src/import/pull-common.h2
-rw-r--r--src/import/pull-dkr.h1
-rw-r--r--src/import/pull-job.h2
-rw-r--r--src/import/pull-raw.h3
-rw-r--r--src/import/pull-tar.c2
-rw-r--r--src/import/pull-tar.h3
-rw-r--r--src/initctl/initctl.c6
-rw-r--r--src/journal-remote/journal-remote-parse.h1
-rw-r--r--src/journal-remote/journal-remote.h4
-rw-r--r--src/journal-remote/journal-upload-journal.c3
-rw-r--r--src/journal-remote/journal-upload.h2
-rw-r--r--src/journal-remote/microhttpd-util.c2
-rw-r--r--src/journal-remote/microhttpd-util.h2
-rw-r--r--src/journal/audit-type.c5
-rw-r--r--src/journal/catalog.h1
-rw-r--r--src/journal/coredump-vacuum.c15
-rw-r--r--src/journal/fsprg.h2
-rw-r--r--src/journal/journal-authenticate.c2
-rw-r--r--src/journal/journal-file.h4
-rw-r--r--src/journal/journal-internal.h2
-rw-r--r--src/journal/journal-qrcode.c7
-rw-r--r--src/journal/journal-verify.c4
-rw-r--r--src/journal/journalctl.c3
-rw-r--r--src/journal/journald-audit.h2
-rw-r--r--src/journal/journald-console.c2
-rw-r--r--src/journal/journald-rate-limit.c6
-rw-r--r--src/journal/journald-server.c10
-rw-r--r--src/journal/journald-wall.c2
-rw-r--r--src/journal/journald.c7
-rw-r--r--src/journal/lookup3.c4
-rw-r--r--src/journal/mmap-cache.c17
-rw-r--r--src/journal/test-catalog.c4
-rw-r--r--src/journal/test-journal-enum.c2
-rw-r--r--src/journal/test-journal-interleaving.c2
-rw-r--r--src/journal/test-journal-verify.c2
-rw-r--r--src/journal/test-journal.c6
-rw-r--r--src/libsystemd-network/arp-util.h2
-rw-r--r--src/libsystemd-network/dhcp-identifier.c12
-rw-r--r--src/libsystemd-network/dhcp-internal.h3
-rw-r--r--src/libsystemd-network/dhcp-lease-internal.h7
-rw-r--r--src/libsystemd-network/dhcp-option.c113
-rw-r--r--src/libsystemd-network/dhcp-packet.c5
-rw-r--r--src/libsystemd-network/dhcp-protocol.h13
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h7
-rw-r--r--src/libsystemd-network/dhcp6-lease-internal.h1
-rw-r--r--src/libsystemd-network/dhcp6-network.c22
-rw-r--r--src/libsystemd-network/dhcp6-option.c20
-rw-r--r--src/libsystemd-network/icmp6-util.c44
-rw-r--r--src/libsystemd-network/lldp-port.c4
-rw-r--r--src/libsystemd-network/lldp-tlv.c2
-rw-r--r--src/libsystemd-network/lldp-tlv.h8
-rw-r--r--src/libsystemd-network/network-internal.c6
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c105
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c21
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c45
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c11
-rw-r--r--src/libsystemd-network/sd-ndisc.c89
-rw-r--r--src/libsystemd-network/test-acd.c8
-rw-r--r--src/libsystemd-network/test-dhcp-client.c8
-rw-r--r--src/libsystemd-network/test-dhcp-option.c26
-rw-r--r--src/libsystemd-network/test-dhcp-server.c4
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c6
-rw-r--r--src/libsystemd/sd-bus/bus-bloom.c10
-rw-r--r--src/libsystemd/sd-bus/bus-bloom.h1
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c3
-rw-r--r--src/libsystemd/sd-bus/bus-container.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.h1
-rw-r--r--src/libsystemd/sd-bus/bus-dump.h2
-rw-r--r--src/libsystemd/sd-bus/bus-error.c2
-rw-r--r--src/libsystemd/sd-bus/bus-error.h1
-rw-r--r--src/libsystemd/sd-bus/bus-gvariant.c2
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.h1
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c2
-rw-r--r--src/libsystemd/sd-bus/bus-slot.c2
-rw-r--r--src/libsystemd/sd-bus/bus-slot.h1
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c8
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c6
-rw-r--r--src/libsystemd/sd-bus/test-bus-creds.c1
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-introspect.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-match.c7
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-signature.c6
-rw-r--r--src/libsystemd/sd-bus/test-bus-zero-copy.c2
-rw-r--r--src/libsystemd/sd-event/sd-event.c47
-rw-r--r--src/libsystemd/sd-event/test-event.c18
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c2
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.c4
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.h1
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.h2
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c2
-rw-r--r--src/libsystemd/sd-netlink/test-local-addresses.c2
-rw-r--r--src/libsystemd/sd-utf8/sd-utf8.c2
-rw-r--r--src/libudev/libudev-private.h2
-rw-r--r--src/libudev/libudev-queue.c6
-rw-r--r--src/login/logind-acl.h2
-rw-r--r--src/login/logind-action.h2
-rw-r--r--src/login/logind-core.c11
-rw-r--r--src/login/logind-dbus.c132
-rw-r--r--src/login/logind-gperf.gperf1
-rw-r--r--src/login/logind-session.c27
-rw-r--r--src/login/logind-session.h2
-rw-r--r--src/login/logind-user.c255
-rw-r--r--src/login/logind-user.h12
-rw-r--r--src/login/logind-utmp.c2
-rw-r--r--src/login/logind.c1
-rw-r--r--src/login/logind.conf1
-rw-r--r--src/login/logind.h4
-rw-r--r--src/login/pam_systemd.c30
-rw-r--r--src/login/test-login-shared.c2
-rw-r--r--src/login/test-login-tables.c1
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c2
-rw-r--r--src/machine/machine.c7
-rw-r--r--src/machine/machined-dbus.c5
-rw-r--r--src/machine/machined.h4
-rw-r--r--src/machine/test-machine-tables.c1
-rw-r--r--src/network/networkctl.c1
-rw-r--r--src/network/networkd-address-pool.h1
-rw-r--r--src/network/networkd-address.c6
-rw-r--r--src/network/networkd-address.h4
-rw-r--r--src/network/networkd-dhcp4.c3
-rw-r--r--src/network/networkd-dhcp6.c8
-rw-r--r--src/network/networkd-fdb.c2
-rw-r--r--src/network/networkd-fdb.h2
-rw-r--r--src/network/networkd-ipv4ll.c8
-rw-r--r--src/network/networkd-link-bus.c5
-rw-r--r--src/network/networkd-link.c45
-rw-r--r--src/network/networkd-link.h8
-rw-r--r--src/network/networkd-ndisc.c10
-rw-r--r--src/network/networkd-netdev-bond.c2
-rw-r--r--src/network/networkd-netdev-bridge.c2
-rw-r--r--src/network/networkd-netdev-tuntap.c2
-rw-r--r--src/network/networkd-netdev-veth.c1
-rw-r--r--src/network/networkd-netdev-vxlan.c5
-rw-r--r--src/network/networkd-netdev-vxlan.h3
-rw-r--r--src/network/networkd-netdev.c6
-rw-r--r--src/network/networkd-netdev.h14
-rw-r--r--src/network/networkd-network.h6
-rw-r--r--src/network/networkd-route.h2
-rw-r--r--src/network/networkd.h6
-rw-r--r--src/network/test-network-tables.c9
-rw-r--r--src/network/test-network.c4
-rw-r--r--src/nspawn/nspawn-cgroup.h2
-rw-r--r--src/nspawn/nspawn-expose-ports.h3
-rw-r--r--src/nspawn/nspawn-network.c8
-rw-r--r--src/nspawn/nspawn-network.h3
-rw-r--r--src/nspawn/nspawn-register.c4
-rw-r--r--src/nspawn/nspawn-settings.h3
-rw-r--r--src/nspawn/nspawn.c6
-rw-r--r--src/nss-mymachines/nss-mymachines.c6
-rw-r--r--src/quotacheck/quotacheck.c2
-rw-r--r--src/remount-fs/remount-fs.c70
-rw-r--r--src/resolve-host/resolve-host.c357
-rw-r--r--src/resolve/resolved-bus.c959
-rw-r--r--src/resolve/resolved-conf.c162
-rw-r--r--src/resolve/resolved-conf.h10
-rw-r--r--src/resolve/resolved-def.h15
-rw-r--r--src/resolve/resolved-dns-answer.c2
-rw-r--r--src/resolve/resolved-dns-answer.h17
-rw-r--r--src/resolve/resolved-dns-cache.c44
-rw-r--r--src/resolve/resolved-dns-cache.h6
-rw-r--r--src/resolve/resolved-dns-packet.c123
-rw-r--r--src/resolve/resolved-dns-packet.h28
-rw-r--r--src/resolve/resolved-dns-query.c614
-rw-r--r--src/resolve/resolved-dns-query.h48
-rw-r--r--src/resolve/resolved-dns-question.c200
-rw-r--r--src/resolve/resolved-dns-question.h21
-rw-r--r--src/resolve/resolved-dns-rr.c179
-rw-r--r--src/resolve/resolved-dns-rr.h21
-rw-r--r--src/resolve/resolved-dns-scope.c117
-rw-r--r--src/resolve/resolved-dns-scope.h24
-rw-r--r--src/resolve/resolved-dns-search-domain.c232
-rw-r--r--src/resolve/resolved-dns-search-domain.h75
-rw-r--r--src/resolve/resolved-dns-server.c299
-rw-r--r--src/resolve/resolved-dns-server.h24
-rw-r--r--src/resolve/resolved-dns-transaction.c81
-rw-r--r--src/resolve/resolved-dns-transaction.h31
-rw-r--r--src/resolve/resolved-dns-zone.c245
-rw-r--r--src/resolve/resolved-dns-zone.h6
-rw-r--r--src/resolve/resolved-gperf.gperf7
-rw-r--r--src/resolve/resolved-link.c97
-rw-r--r--src/resolve/resolved-link.h10
-rw-r--r--src/resolve/resolved-llmnr.c2
-rw-r--r--src/resolve/resolved-manager.c496
-rw-r--r--src/resolve/resolved-manager.h31
-rw-r--r--src/resolve/resolved-resolv-conf.c273
-rw-r--r--src/resolve/resolved-resolv-conf.h27
-rw-r--r--src/resolve/resolved.c7
-rw-r--r--src/resolve/resolved.conf.in1
-rw-r--r--src/run/run.c78
-rw-r--r--src/shared/acl-util.c2
-rw-r--r--src/shared/acl-util.h2
-rw-r--r--src/shared/acpi-fpdt.c2
-rw-r--r--src/shared/architecture.c2
-rw-r--r--src/shared/boot-timestamps.c2
-rw-r--r--src/shared/bus-util.c32
-rw-r--r--src/shared/cgroup-show.h1
-rw-r--r--src/shared/clean-ipc.c2
-rw-r--r--src/shared/conf-parser.h2
-rw-r--r--src/shared/dns-domain.c425
-rw-r--r--src/shared/dns-domain.h19
-rw-r--r--src/shared/efivars.c4
-rw-r--r--src/shared/efivars.h1
-rw-r--r--src/shared/firewall-util.c2
-rw-r--r--src/shared/install.c2
-rw-r--r--src/shared/logs-show.h2
-rw-r--r--src/shared/machine-image.h4
-rw-r--r--src/shared/nss-util.h6
-rw-r--r--src/shared/path-lookup.c12
-rw-r--r--src/shared/ptyfwd.c2
-rw-r--r--src/shared/seccomp-util.c2
-rw-r--r--src/shared/spawn-ask-password-agent.c2
-rw-r--r--src/shared/spawn-polkit-agent.c6
-rw-r--r--src/shared/sysctl-util.c2
-rw-r--r--src/shared/watchdog.c6
-rw-r--r--src/systemctl/systemctl.c23
-rw-r--r--src/systemd/sd-bus.h3
-rw-r--r--src/systemd/sd-daemon.h2
-rw-r--r--src/systemd/sd-device.h2
-rw-r--r--src/systemd/sd-dhcp-client.h2
-rw-r--r--src/systemd/sd-dhcp-server.h1
-rw-r--r--src/systemd/sd-dhcp6-client.h3
-rw-r--r--src/systemd/sd-event.h13
-rw-r--r--src/systemd/sd-ipv4acd.h3
-rw-r--r--src/systemd/sd-ipv4ll.h3
-rw-r--r--src/systemd/sd-journal.h3
-rw-r--r--src/systemd/sd-lldp.h3
-rw-r--r--src/systemd/sd-login.h2
-rw-r--r--src/systemd/sd-messages.h1
-rw-r--r--src/systemd/sd-ndisc.h1
-rw-r--r--src/systemd/sd-netlink.h3
-rw-r--r--src/systemd/sd-network.h2
-rw-r--r--src/systemd/sd-resolve.h1
-rw-r--r--src/test/test-architecture.c4
-rw-r--r--src/test/test-boot-timestamps.c6
-rw-r--r--src/test/test-calendarspec.c13
-rw-r--r--src/test/test-cgroup-mask.c14
-rw-r--r--src/test/test-dns-domain.c179
-rw-r--r--src/test/test-engine.c4
-rw-r--r--src/test/test-fileio.c2
-rw-r--r--src/test/test-firewall-util.c2
-rw-r--r--src/test/test-hashmap.c2
-rw-r--r--src/test/test-install.c2
-rw-r--r--src/test/test-job-type.c2
-rw-r--r--src/test/test-locale-util.c2
-rw-r--r--src/test/test-log.c2
-rw-r--r--src/test/test-loopback.c4
-rw-r--r--src/test/test-ns.c2
-rw-r--r--src/test/test-ratelimit.c2
-rw-r--r--src/test/test-sched-prio.c2
-rw-r--r--src/test/test-siphash24.c49
-rw-r--r--src/test/test-sleep.c2
-rw-r--r--src/test/test-tables.c5
-rw-r--r--src/test/test-terminal-util.c2
-rw-r--r--src/test/test-time.c2
-rw-r--r--src/test/test-unaligned.c76
-rw-r--r--src/test/test-unit-file.c51
-rw-r--r--src/test/test-utf8.c2
-rw-r--r--src/test/test-watchdog.c2
-rw-r--r--src/timesync/timesyncd-conf.h1
-rw-r--r--src/timesync/timesyncd-manager.h3
-rw-r--r--src/timesync/timesyncd-server.h2
-rw-r--r--src/tmpfiles/tmpfiles.c24
-rw-r--r--src/udev/mtd_probe/mtd_probe.c8
-rw-r--r--src/udev/mtd_probe/probe_smartmedia.c9
-rw-r--r--src/udev/net/link-config.c6
-rw-r--r--src/udev/udev-builtin-path_id.c57
-rw-r--r--src/udev/udev-builtin-uaccess.c2
-rw-r--r--src/udev/udev-ctrl.c6
-rw-r--r--src/udev/udev-watch.c6
-rw-r--r--src/udev/udevadm-control.c6
-rw-r--r--src/udev/udevadm-monitor.c12
-rw-r--r--src/udev/udevadm-settle.c10
-rw-r--r--src/udev/udevd.c8
-rw-r--r--src/udev/v4l_id/v4l_id.c14
429 files changed, 6821 insertions, 2877 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index b7e45dcfd6..e922d6fb32 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -1066,23 +1066,23 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro
assert(bus);
assert(u);
- if (arg_dot == DEP_ORDER ||arg_dot == DEP_ALL) {
+ if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) {
r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
}
- if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) {
+ if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) {
r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
- r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
+ r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
- r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
+ r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
- r = graph_one_property(bus, u, "ConflictedBy", "red", patterns, from_patterns, to_patterns);
+ r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
}
diff --git a/src/basic/af-list.c b/src/basic/af-list.c
index f396115a34..07dfff6ad4 100644
--- a/src/basic/af-list.c
+++ b/src/basic/af-list.c
@@ -19,16 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <string.h>
+#include <sys/socket.h>
-#include "util.h"
#include "af-list.h"
+#include "util.h"
static const struct af_name* lookup_af(register const char *str, register unsigned int len);
-#include "af-to-name.h"
#include "af-from-name.h"
+#include "af-to-name.h"
const char *af_to_name(int id) {
diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c
index 284043cd90..03d8ad7403 100644
--- a/src/basic/arphrd-list.c
+++ b/src/basic/arphrd-list.c
@@ -22,13 +22,13 @@
#include <net/if_arp.h>
#include <string.h>
-#include "util.h"
#include "arphrd-list.h"
+#include "util.h"
static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len);
-#include "arphrd-to-name.h"
#include "arphrd-from-name.h"
+#include "arphrd-to-name.h"
const char *arphrd_to_name(int id) {
diff --git a/src/basic/async.c b/src/basic/async.c
index c3135f0efe..cfc5d224e1 100644
--- a/src/basic/async.c
+++ b/src/basic/async.c
@@ -68,7 +68,7 @@ int asynchronous_sync(void) {
}
static void *close_thread(void *p) {
- assert_se(close_nointr(PTR_TO_INT(p)) != -EBADF);
+ assert_se(close_nointr(PTR_TO_FD(p)) != -EBADF);
return NULL;
}
@@ -84,7 +84,7 @@ int asynchronous_close(int fd) {
if (fd >= 0) {
PROTECT_ERRNO;
- r = asynchronous_job(close_thread, INT_TO_PTR(fd));
+ r = asynchronous_job(close_thread, FD_TO_PTR(fd));
if (r < 0)
assert_se(close_nointr(fd) != -EBADF);
}
diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h
index 6de331c73e..026d3cd9b1 100644
--- a/src/basic/audit-util.h
+++ b/src/basic/audit-util.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <sys/types.h>
#define AUDIT_SESSION_INVALID ((uint32_t) -1)
diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h
index 2874bc99f7..9ce7b42d00 100644
--- a/src/basic/bitmap.h
+++ b/src/basic/bitmap.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
#include "hashmap.h"
+#include "macro.h"
typedef struct Bitmap Bitmap;
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 290fabdeff..be40dc5702 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -105,7 +105,7 @@ int btrfs_is_filesystem(int fd) {
return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
}
-int btrfs_is_subvol(int fd) {
+int btrfs_is_subvol_fd(int fd) {
struct stat st;
assert(fd >= 0);
@@ -121,6 +121,18 @@ int btrfs_is_subvol(int fd) {
return btrfs_is_filesystem(fd);
}
+int btrfs_is_subvol(const char *path) {
+ _cleanup_close_ int fd = -1;
+
+ assert(path);
+
+ fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_is_subvol_fd(fd);
+}
+
int btrfs_subvol_make(const char *path) {
struct btrfs_ioctl_vol_args args = {};
_cleanup_close_ int fd = -1;
@@ -1423,12 +1435,16 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub
return n_old_qgroups;
r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
- if (r < 0)
+ if (r == -ENXIO)
+ /* We have no parent, hence nothing to copy. */
+ n_old_parent_qgroups = 0;
+ else if (r < 0)
return r;
-
- n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
- if (n_old_parent_qgroups < 0)
- return n_old_parent_qgroups;
+ else {
+ n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
+ if (n_old_parent_qgroups < 0)
+ return n_old_parent_qgroups;
+ }
for (i = 0; i < n_old_qgroups; i++) {
uint64_t id;
@@ -1682,7 +1698,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
assert(old_fd >= 0);
assert(new_path);
- r = btrfs_is_subvol(old_fd);
+ r = btrfs_is_subvol_fd(old_fd);
if (r < 0)
return r;
if (r == 0) {
@@ -1868,7 +1884,7 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
*/
if (subvol_id == 0) {
- r = btrfs_is_subvol(fd);
+ r = btrfs_is_subvol_fd(fd);
if (r < 0)
return r;
if (!r)
@@ -1885,14 +1901,19 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
if (n > 0) /* already parent qgroups set up, let's bail */
return 0;
+ qgroups = mfree(qgroups);
+
r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
- if (r < 0)
+ if (r == -ENXIO)
+ /* No parent, hence no qgroup memberships */
+ n = 0;
+ else if (r < 0)
return r;
-
- qgroups = mfree(qgroups);
- n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
- if (n < 0)
- return n;
+ else {
+ n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
+ if (n < 0)
+ return n;
+ }
if (insert_intermediary_qgroup) {
uint64_t lowest = 256, new_qgroupid;
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index fc9efd72d5..8c11ce35d2 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -56,7 +56,9 @@ typedef enum BtrfsRemoveFlags {
} BtrfsRemoveFlags;
int btrfs_is_filesystem(int fd);
-int btrfs_is_subvol(int fd);
+
+int btrfs_is_subvol_fd(int fd);
+int btrfs_is_subvol(const char *path);
int btrfs_reflink(int infd, int outfd);
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 7151fc3d0c..8f60561ede 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -23,9 +23,10 @@
#include <string.h>
#include "alloc-util.h"
-#include "string-util.h"
#include "calendarspec.h"
#include "fileio.h"
+#include "parse-util.h"
+#include "string-util.h"
#define BITS_WEEKDAYS 127
@@ -49,7 +50,7 @@ void calendar_spec_free(CalendarSpec *c) {
free_chain(c->day);
free_chain(c->hour);
free_chain(c->minute);
- free_chain(c->second);
+ free_chain(c->microsecond);
free(c);
}
@@ -135,7 +136,7 @@ int calendar_spec_normalize(CalendarSpec *c) {
sort_chain(&c->day);
sort_chain(&c->hour);
sort_chain(&c->minute);
- sort_chain(&c->second);
+ sort_chain(&c->microsecond);
return 0;
}
@@ -177,7 +178,7 @@ _pure_ bool calendar_spec_valid(CalendarSpec *c) {
if (!chain_valid(c->minute, 0, 59))
return false;
- if (!chain_valid(c->second, 0, 59))
+ if (!chain_valid(c->microsecond, 0, 60*USEC_PER_SEC-1))
return false;
return true;
@@ -232,7 +233,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
}
}
-static void format_chain(FILE *f, int space, const CalendarComponent *c) {
+static void format_chain(FILE *f, int space, const CalendarComponent *c, bool usec) {
assert(f);
if (!c) {
@@ -241,14 +242,25 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c) {
}
assert(c->value >= 0);
- fprintf(f, "%0*i", space, c->value);
-
- if (c->repeat > 0)
- fprintf(f, "/%i", c->repeat);
+ if (!usec)
+ fprintf(f, "%0*i", space, c->value);
+ else if (c->value % USEC_PER_SEC == 0)
+ fprintf(f, "%0*i", space, (int) (c->value / USEC_PER_SEC));
+ else
+ fprintf(f, "%0*i.%06i", space, (int) (c->value / USEC_PER_SEC), (int) (c->value % USEC_PER_SEC));
+
+ if (c->repeat > 0) {
+ if (!usec)
+ fprintf(f, "/%i", c->repeat);
+ else if (c->repeat % USEC_PER_SEC == 0)
+ fprintf(f, "/%i", (int) (c->repeat / USEC_PER_SEC));
+ else
+ fprintf(f, "/%i.%06i", (int) (c->repeat / USEC_PER_SEC), (int) (c->repeat % USEC_PER_SEC));
+ }
if (c->next) {
fputc(',', f);
- format_chain(f, space, c->next);
+ format_chain(f, space, c->next, usec);
}
}
@@ -270,17 +282,17 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
fputc(' ', f);
}
- format_chain(f, 4, c->year);
+ format_chain(f, 4, c->year, false);
fputc('-', f);
- format_chain(f, 2, c->month);
+ format_chain(f, 2, c->month, false);
fputc('-', f);
- format_chain(f, 2, c->day);
+ format_chain(f, 2, c->day, false);
fputc(' ', f);
- format_chain(f, 2, c->hour);
+ format_chain(f, 2, c->hour, false);
fputc(':', f);
- format_chain(f, 2, c->minute);
+ format_chain(f, 2, c->minute, false);
fputc(':', f);
- format_chain(f, 2, c->second);
+ format_chain(f, 2, c->microsecond, true);
if (c->utc)
fputs(" UTC", f);
@@ -391,35 +403,70 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
}
}
-static int prepend_component(const char **p, CalendarComponent **c) {
- unsigned long value, repeat = 0;
- char *e = NULL, *ee = NULL;
- CalendarComponent *cc;
-
- assert(p);
- assert(c);
+static int parse_component_decimal(const char **p, bool usec, unsigned long *res) {
+ unsigned long value;
+ const char *e = NULL;
+ char *ee = NULL;
+ int r;
errno = 0;
- value = strtoul(*p, &e, 10);
+ value = strtoul(*p, &ee, 10);
if (errno > 0)
return -errno;
- if (e == *p)
+ if (ee == *p)
return -EINVAL;
if ((unsigned long) (int) value != value)
return -ERANGE;
+ e = ee;
- if (*e == '/') {
- repeat = strtoul(e+1, &ee, 10);
- if (errno > 0)
- return -errno;
- if (ee == e+1)
- return -EINVAL;
- if ((unsigned long) (int) repeat != repeat)
- return -ERANGE;
- if (repeat <= 0)
+ if (usec) {
+ if (value * USEC_PER_SEC / USEC_PER_SEC != value)
return -ERANGE;
- e = ee;
+ value *= USEC_PER_SEC;
+ if (*e == '.') {
+ unsigned add;
+
+ e++;
+ r = parse_fractional_part_u(&e, 6, &add);
+ if (r < 0)
+ return r;
+
+ if (add + value < value)
+ return -ERANGE;
+ value += add;
+ }
+ }
+
+ *p = e;
+ *res = value;
+
+ return 0;
+}
+
+static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
+ unsigned long value, repeat = 0;
+ CalendarComponent *cc;
+ int r;
+ const char *e;
+
+ assert(p);
+ assert(c);
+
+ e = *p;
+
+ r = parse_component_decimal(&e, usec, &value);
+ if (r < 0)
+ return r;
+
+ if (*e == '/') {
+ e++;
+ r = parse_component_decimal(&e, usec, &repeat);
+ if (r < 0)
+ return r;
+
+ if (repeat == 0)
+ return -ERANGE;
}
if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':')
@@ -438,13 +485,31 @@ static int prepend_component(const char **p, CalendarComponent **c) {
if (*e ==',') {
*p += 1;
- return prepend_component(p, c);
+ return prepend_component(p, usec, c);
}
return 0;
}
-static int parse_chain(const char **p, CalendarComponent **c) {
+static int const_chain(int value, CalendarComponent **c) {
+ CalendarComponent *cc = NULL;
+
+ assert(c);
+
+ cc = new0(CalendarComponent, 1);
+ if (!cc)
+ return -ENOMEM;
+
+ cc->value = value;
+ cc->repeat = 0;
+ cc->next = *c;
+
+ *c = cc;
+
+ return 0;
+}
+
+static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
const char *t;
CalendarComponent *cc = NULL;
int r;
@@ -455,12 +520,19 @@ static int parse_chain(const char **p, CalendarComponent **c) {
t = *p;
if (t[0] == '*') {
+ if (usec) {
+ r = const_chain(0, c);
+ if (r < 0)
+ return r;
+ (*c)->repeat = USEC_PER_SEC;
+ } else
+ *c = NULL;
+
*p = t + 1;
- *c = NULL;
return 0;
}
- r = prepend_component(&t, &cc);
+ r = prepend_component(&t, usec, &cc);
if (r < 0) {
free_chain(cc);
return r;
@@ -471,24 +543,6 @@ static int parse_chain(const char **p, CalendarComponent **c) {
return 0;
}
-static int const_chain(int value, CalendarComponent **c) {
- CalendarComponent *cc = NULL;
-
- assert(c);
-
- cc = new0(CalendarComponent, 1);
- if (!cc)
- return -ENOMEM;
-
- cc->value = value;
- cc->repeat = 0;
- cc->next = *c;
-
- *c = cc;
-
- return 0;
-}
-
static int parse_date(const char **p, CalendarSpec *c) {
const char *t;
int r;
@@ -503,7 +557,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
if (*t == 0)
return 0;
- r = parse_chain(&t, &first);
+ r = parse_chain(&t, false, &first);
if (r < 0)
return r;
@@ -519,7 +573,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
t++;
- r = parse_chain(&t, &second);
+ r = parse_chain(&t, false, &second);
if (r < 0) {
free_chain(first);
return r;
@@ -540,7 +594,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
t++;
- r = parse_chain(&t, &third);
+ r = parse_chain(&t, false, &third);
if (r < 0) {
free_chain(first);
free_chain(second);
@@ -582,7 +636,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
goto finish;
}
- r = parse_chain(&t, &h);
+ r = parse_chain(&t, false, &h);
if (r < 0)
goto fail;
@@ -592,7 +646,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
}
t++;
- r = parse_chain(&t, &m);
+ r = parse_chain(&t, false, &m);
if (r < 0)
goto fail;
@@ -610,7 +664,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
}
t++;
- r = parse_chain(&t, &s);
+ r = parse_chain(&t, true, &s);
if (r < 0)
goto fail;
@@ -639,7 +693,8 @@ finish:
*p = t;
c->hour = h;
c->minute = m;
- c->second = s;
+ c->microsecond = s;
+
return 0;
fail:
@@ -671,7 +726,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
}
if (strcaseeq(p, "minutely")) {
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -679,7 +734,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -690,7 +745,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -704,7 +759,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -724,7 +779,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -738,7 +793,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -765,7 +820,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -789,7 +844,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
r = const_chain(0, &c->minute);
if (r < 0)
goto fail;
- r = const_chain(0, &c->second);
+ r = const_chain(0, &c->microsecond);
if (r < 0)
goto fail;
@@ -906,14 +961,16 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
return (weekdays_bits & (1 << k));
}
-static int find_next(const CalendarSpec *spec, struct tm *tm) {
+static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
struct tm c;
+ int tm_usec;
int r;
assert(spec);
assert(tm);
c = *tm;
+ tm_usec = *usec;
for (;;) {
/* Normalize the current date */
@@ -927,7 +984,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
if (r > 0) {
c.tm_mon = 0;
c.tm_mday = 1;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
}
if (r < 0 || tm_out_of_bounds(&c, spec->utc))
return r;
@@ -938,29 +995,29 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
if (r > 0) {
c.tm_mday = 1;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
}
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_year ++;
c.tm_mon = 0;
c.tm_mday = 1;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
r = find_matching_component(spec->day, &c.tm_mday);
if (r > 0)
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mon ++;
c.tm_mday = 1;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
c.tm_mday++;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
@@ -969,7 +1026,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_min = c.tm_sec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mday ++;
- c.tm_hour = c.tm_min = c.tm_sec = 0;
+ c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
@@ -978,19 +1035,23 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_sec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_hour ++;
- c.tm_min = c.tm_sec = 0;
+ c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
- r = find_matching_component(spec->second, &c.tm_sec);
+ c.tm_sec = c.tm_sec * USEC_PER_SEC + tm_usec;
+ r = find_matching_component(spec->microsecond, &c.tm_sec);
+ tm_usec = c.tm_sec % USEC_PER_SEC;
+ c.tm_sec /= USEC_PER_SEC;
+
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_min ++;
- c.tm_sec = 0;
+ c.tm_sec = tm_usec = 0;
continue;
}
-
*tm = c;
+ *usec = tm_usec;
return 0;
}
}
@@ -999,14 +1060,17 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
struct tm tm;
time_t t;
int r;
+ usec_t tm_usec;
assert(spec);
assert(next);
- t = (time_t) (usec / USEC_PER_SEC) + 1;
+ usec++;
+ t = (time_t) (usec / USEC_PER_SEC);
assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
+ tm_usec = usec % USEC_PER_SEC;
- r = find_next(spec, &tm);
+ r = find_next(spec, &tm, &tm_usec);
if (r < 0)
return r;
@@ -1014,6 +1078,6 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
if (t == (time_t) -1)
return -EINVAL;
- *next = (usec_t) t * USEC_PER_SEC;
+ *next = (usec_t) t * USEC_PER_SEC + tm_usec;
return 0;
}
diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h
index 56dc02f391..75b699682a 100644
--- a/src/basic/calendarspec.h
+++ b/src/basic/calendarspec.h
@@ -25,6 +25,7 @@
* time, a la cron */
#include <stdbool.h>
+
#include "util.h"
typedef struct CalendarComponent {
@@ -44,7 +45,7 @@ typedef struct CalendarSpec {
CalendarComponent *hour;
CalendarComponent *minute;
- CalendarComponent *second;
+ CalendarComponent *microsecond;
} CalendarSpec;
void calendar_spec_free(CalendarSpec *c);
diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c
index 4d391510bc..f0974900cd 100644
--- a/src/basic/cap-list.c
+++ b/src/basic/cap-list.c
@@ -28,8 +28,8 @@
static const struct capability_name* lookup_capability(register const char *str, register unsigned int len);
-#include "cap-to-name.h"
#include "cap-from-name.h"
+#include "cap-to-name.h"
const char *capability_to_name(int id) {
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 01359fa7cb..a80ee60bd3 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -21,12 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <stdio.h>
#include <dirent.h>
+#include <stdio.h>
+#include <sys/types.h>
-#include "set.h"
#include "def.h"
+#include "set.h"
/* An enum of well known cgroup controllers */
typedef enum CGroupController {
diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c
index 34d1331486..22869e4136 100644
--- a/src/basic/errno-list.c
+++ b/src/basic/errno-list.c
@@ -21,14 +21,14 @@
#include <string.h>
-#include "util.h"
#include "errno-list.h"
+#include "util.h"
static const struct errno_name* lookup_errno(register const char *str,
register unsigned int len);
-#include "errno-to-name.h"
#include "errno-from-name.h"
+#include "errno-to-name.h"
const char *errno_to_name(int id) {
diff --git a/src/basic/escape.c b/src/basic/escape.c
index 4815161b09..42a84c9317 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -89,20 +89,20 @@ size_t cescape_char(char c, char *buf) {
return buf - buf_old;
}
-char *cescape(const char *s) {
- char *r, *t;
+char *cescape_length(const char *s, size_t n) {
const char *f;
+ char *r, *t;
- assert(s);
+ assert(s || n == 0);
/* Does C style string escaping. May be reversed with
* cunescape(). */
- r = new(char, strlen(s)*4 + 1);
+ r = new(char, n*4 + 1);
if (!r)
return NULL;
- for (f = s, t = r; *f; f++)
+ for (f = s, t = r; f < s + n; f++)
t += cescape_char(*f, t);
*t = 0;
@@ -110,6 +110,12 @@ char *cescape(const char *s) {
return r;
}
+char *cescape(const char *s) {
+ assert(s);
+
+ return cescape_length(s, strlen(s));
+}
+
int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
int r = 1;
diff --git a/src/basic/escape.h b/src/basic/escape.h
index 85ba909081..52ebf11c4a 100644
--- a/src/basic/escape.h
+++ b/src/basic/escape.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
@@ -35,6 +35,7 @@ typedef enum UnescapeFlags {
} UnescapeFlags;
char *cescape(const char *s);
+char *cescape_length(const char *s, size_t n);
size_t cescape_char(char c, char *buf);
int cunescape(const char *s, UnescapeFlags flags, char **ret);
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index fcff753ada..4c83731540 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -19,12 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <signal.h>
+#include <stdlib.h>
#include "exit-status.h"
-#include "set.h"
#include "macro.h"
+#include "set.h"
const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
index 1ca10f0383..5ce1592eeb 100644
--- a/src/basic/fd-util.h
+++ b/src/basic/fd-util.h
@@ -21,13 +21,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <dirent.h>
#include <stdbool.h>
+#include <stdio.h>
#include <sys/socket.h>
#include "macro.h"
+/* Make sure we can distinguish fd 0 and NULL */
+#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
+#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
+
int close_nointr(int fd);
int safe_close(int fd);
void safe_close_pair(int p[]);
diff --git a/src/basic/fdset.c b/src/basic/fdset.c
index 42b0b2b98f..e5452f3bb0 100644
--- a/src/basic/fdset.c
+++ b/src/basic/fdset.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include "sd-daemon.h"
@@ -36,10 +36,6 @@
#define MAKE_SET(s) ((Set*) s)
#define MAKE_FDSET(s) ((FDSet*) s)
-/* Make sure we can distinguish fd 0 and NULL */
-#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
-#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
-
FDSet *fdset_new(void) {
return MAKE_FDSET(set_new(NULL));
}
diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c
index f596f1d11f..0405822ce0 100644
--- a/src/basic/fileio-label.c
+++ b/src/basic/fileio-label.c
@@ -20,9 +20,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "selinux-util.h"
#include "fileio-label.h"
+#include "selinux-util.h"
+#include "util.h"
int write_string_file_atomic_label(const char *fn, const char *line) {
int r;
diff --git a/src/basic/fileio-label.h b/src/basic/fileio-label.h
index 25fa351be2..9feb3cccb5 100644
--- a/src/basic/fileio-label.h
+++ b/src/basic/fileio-label.h
@@ -23,6 +23,7 @@
***/
#include <stdio.h>
+
#include "fileio.h"
int write_string_file_atomic_label(const char *fn, const char *line);
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 902c7e295b..5fbb7bc4c3 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -22,10 +22,10 @@
***/
#include <fcntl.h>
+#include <limits.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
-#include <limits.h>
#include "time-util.h"
diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h
index e70818fdd7..b03aa43160 100644
--- a/src/basic/gunicode.h
+++ b/src/basic/gunicode.h
@@ -6,8 +6,8 @@
#pragma once
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
char *utf8_prev_char (const char *p);
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 4109a08c6c..6e501ef6ff 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -380,7 +380,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
h->hash_ops->hash(p, &state);
- siphash24_finalize((uint8_t*)&hash, &state);
+ hash = siphash24_finalize(&state);
return (unsigned) (hash % n_buckets(h));
}
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index ea0528c6fc..c57a3cbd60 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -72,7 +72,7 @@ static bool hostname_valid_char(char c) {
* allow_trailing_dot is true and at least two components are present
* in the name. Note that due to the restricted charset and length
* this call is substantially more conservative than
- * dns_domain_is_valid().
+ * dns_name_is_valid().
*/
bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
unsigned n_dots = 0;
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index f4e24121e7..b75c39aac7 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -44,7 +44,7 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return (be32toh(u->in.s_addr) & 0xFFFF0000) == (169U << 24 | 254U << 16);
+ return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
if (family == AF_INET6)
return IN6_IS_ADDR_LINKLOCAL(&u->in6);
@@ -52,6 +52,19 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) {
return -EAFNOSUPPORT;
}
+int in_addr_is_localhost(int family, const union in_addr_union *u) {
+ assert(u);
+
+ if (family == AF_INET)
+ /* All of 127.x.x.x is localhost. */
+ return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
+
+ if (family == AF_INET6)
+ return IN6_IS_ADDR_LOOPBACK(&u->in6);
+
+ return -EAFNOSUPPORT;
+}
+
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
assert(a);
assert(b);
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index 51af08868c..58f55b3418 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -33,6 +33,7 @@ union in_addr_union {
int in_addr_is_null(int family, const union in_addr_union *u);
int in_addr_is_link_local(int family, const union in_addr_union *u);
+int in_addr_is_localhost(int family, const union in_addr_union *u);
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
diff --git a/src/basic/ioprio.h b/src/basic/ioprio.h
index e5c71d0043..d8bb6eb497 100644
--- a/src/basic/ioprio.h
+++ b/src/basic/ioprio.h
@@ -4,8 +4,8 @@
/* This is minimal version of Linux' linux/ioprio.h header file, which
* is licensed GPL2 */
-#include <unistd.h>
#include <sys/syscall.h>
+#include <unistd.h>
/*
* Gives us 8 prio classes with 13-bits of data for each class
diff --git a/src/basic/json.c b/src/basic/json.c
index 716705e5ff..9d5dedb934 100644
--- a/src/basic/json.c
+++ b/src/basic/json.c
@@ -23,9 +23,9 @@
#include <sys/types.h>
#include "alloc-util.h"
+#include "hexdecoct.h"
#include "json.h"
#include "macro.h"
-#include "hexdecoct.h"
#include "string-util.h"
#include "utf8.h"
diff --git a/src/basic/json.h b/src/basic/json.h
index e0b4d810b5..8a7d79cb17 100644
--- a/src/basic/json.h
+++ b/src/basic/json.h
@@ -22,6 +22,7 @@
***/
#include <stdbool.h>
+
#include "util.h"
enum {
diff --git a/src/basic/label.c b/src/basic/label.c
index 82f10b21bd..f33502f90f 100644
--- a/src/basic/label.c
+++ b/src/basic/label.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "label.h"
#include "selinux-util.h"
#include "smack-util.h"
#include "util.h"
-#include "label.h"
int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
int r, q;
diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c
index 87c3aef7af..0bdbae480b 100644
--- a/src/basic/lockfile-util.c
+++ b/src/basic/lockfile-util.c
@@ -19,12 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/file.h>
#include "alloc-util.h"
diff --git a/src/basic/login-util.c b/src/basic/login-util.c
index 832f477bd2..41cef14e73 100644
--- a/src/basic/login-util.c
+++ b/src/basic/login-util.c
@@ -20,8 +20,8 @@
***/
#include "def.h"
-#include "string-util.h"
#include "login-util.h"
+#include "string-util.h"
bool session_id_valid(const char *id) {
diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h
index 2cb404ea81..3e4de008a4 100644
--- a/src/basic/memfd-util.h
+++ b/src/basic/memfd-util.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
int memfd_new(const char *name);
int memfd_new_and_map(const char *name, size_t sz, void **p);
diff --git a/src/basic/mempool.c b/src/basic/mempool.c
index d5d98d8829..9ee6e6a76d 100644
--- a/src/basic/mempool.c
+++ b/src/basic/mempool.c
@@ -20,8 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "mempool.h"
#include "macro.h"
+#include "mempool.h"
#include "util.h"
struct pool {
diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c
index 76bbc1edda..c241ef6064 100644
--- a/src/basic/mkdir-label.c
+++ b/src/basic/mkdir-label.c
@@ -20,8 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdio.h>
+#include <unistd.h>
#include "label.h"
#include "mkdir.h"
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 0214c4627e..5d7fb9a12d 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
+#include <string.h>
#include "fs-util.h"
#include "mkdir.h"
diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
index 6c617ab305..da10e90ff2 100644
--- a/src/basic/ordered-set.h
+++ b/src/basic/ordered-set.h
@@ -29,6 +29,17 @@ static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) {
return (OrderedSet*) ordered_hashmap_new(ops);
}
+static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops) {
+ if (*s)
+ return 0;
+
+ *s = ordered_set_new(ops);
+ if (!*s)
+ return -ENOMEM;
+
+ return 0;
+}
+
static inline OrderedSet* ordered_set_free(OrderedSet *s) {
ordered_hashmap_free((OrderedHashmap*) s);
return NULL;
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 151067e916..3ae99d9334 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -490,3 +490,39 @@ int safe_atod(const char *s, double *ret_d) {
*ret_d = (double) d;
return 0;
}
+
+int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
+ size_t i;
+ unsigned val = 0;
+ const char *s;
+
+ s = *p;
+
+ /* accept any number of digits, strtoull is limted to 19 */
+ for(i=0; i < digits; i++,s++) {
+ if (*s < '0' || *s > '9') {
+ if (i == 0)
+ return -EINVAL;
+
+ /* too few digits, pad with 0 */
+ for (; i < digits; i++)
+ val *= 10;
+
+ break;
+ }
+
+ val *= 10;
+ val += *s - '0';
+ }
+
+ /* maybe round up */
+ if (*s >= '5' && *s <= '9')
+ val++;
+
+ s += strspn(s, DIGITS);
+
+ *p = s;
+ *res = val;
+
+ return 0;
+}
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 408690d0b3..125de53d7a 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -90,3 +90,5 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
#endif
int safe_atod(const char *s, double *ret_d);
+
+int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index 72633ebf70..fdc7e1bdef 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -19,12 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-#include <sys/types.h>
#include <alloca.h>
+#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
-#include <signal.h>
+#include <sys/types.h>
#include "formats-util.h"
#include "macro.h"
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index a821a3d5bb..e8ce5cfd96 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -24,15 +24,15 @@
#include <sys/un.h>
#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#include <selinux/label.h>
#include <selinux/context.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#endif
#include "alloc-util.h"
-#include "strv.h"
#include "path-util.h"
#include "selinux-util.h"
+#include "strv.h"
#ifdef HAVE_SELINUX
DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
index 2afcaec183..d19984c5fe 100644
--- a/src/basic/selinux-util.h
+++ b/src/basic/selinux-util.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <stdbool.h>
+#include <sys/socket.h>
#include "macro.h"
diff --git a/src/basic/set.h b/src/basic/set.h
index 4554ef2d49..5fd7de08f9 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -27,7 +27,6 @@
Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
-
static inline Set *set_free(Set *s) {
internal_hashmap_free(HASHMAP_BASE(s));
return NULL;
diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c
index 0108603fe8..c535c89d52 100644
--- a/src/basic/sigbus.c
+++ b/src/basic/sigbus.c
@@ -23,8 +23,8 @@
#include <sys/mman.h>
#include "macro.h"
-#include "util.h"
#include "sigbus.h"
+#include "util.h"
#define SIGBUS_QUEUE_MAX 64
diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c
index 3b61961389..10fc56da69 100644
--- a/src/basic/siphash24.c
+++ b/src/basic/siphash24.c
@@ -17,9 +17,9 @@
coding style)
*/
-#include "sparse-endian.h"
-
#include "siphash24.h"
+#include "sparse-endian.h"
+#include "unaligned.h"
#include "util.h"
static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
@@ -53,37 +53,40 @@ void siphash24_init(struct siphash *state, const uint8_t k[16]) {
assert(state);
assert(k);
- k0 = le64toh(*(le64_t*) k);
- k1 = le64toh(*(le64_t*) (k + 8));
-
- /* "somepseudorandomlygeneratedbytes" */
- state->v0 = 0x736f6d6570736575ULL ^ k0;
- state->v1 = 0x646f72616e646f6dULL ^ k1;
- state->v2 = 0x6c7967656e657261ULL ^ k0;
- state->v3 = 0x7465646279746573ULL ^ k1;
- state->padding = 0;
- state->inlen = 0;
+ k0 = unaligned_read_le64(k);
+ k1 = unaligned_read_le64(k + 8);
+
+ *state = (struct siphash) {
+ /* "somepseudorandomlygeneratedbytes" */
+ .v0 = 0x736f6d6570736575ULL ^ k0,
+ .v1 = 0x646f72616e646f6dULL ^ k1,
+ .v2 = 0x6c7967656e657261ULL ^ k0,
+ .v3 = 0x7465646279746573ULL ^ k1,
+ .padding = 0,
+ .inlen = 0,
+ };
}
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
- uint64_t m;
+
const uint8_t *in = _in;
const uint8_t *end = in + inlen;
- unsigned left = state->inlen & 7;
+ size_t left = state->inlen & 7;
+ uint64_t m;
assert(in);
assert(state);
- /* update total length */
+ /* Update total length */
state->inlen += inlen;
- /* if padding exists, fill it out */
+ /* If padding exists, fill it out */
if (left > 0) {
- for ( ; in < end && left < 8; in ++, left ++ )
- state->padding |= ( ( uint64_t )*in ) << (left * 8);
+ for ( ; in < end && left < 8; in ++, left ++)
+ state->padding |= ((uint64_t) *in) << (left * 8);
if (in == end && left < 8)
- /* we did not have enough input to fill out the padding completely */
+ /* We did not have enough input to fill out the padding completely */
return;
#ifdef DEBUG
@@ -93,6 +96,7 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
#endif
+
state->v3 ^= state->padding;
sipround(state);
sipround(state);
@@ -101,10 +105,10 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
state->padding = 0;
}
- end -= ( state->inlen % sizeof (uint64_t) );
+ end -= (state->inlen % sizeof(uint64_t));
- for ( ; in < end; in += 8 ) {
- m = le64toh(*(le64_t*) in);
+ for ( ; in < end; in += 8) {
+ m = unaligned_read_le64(in);
#ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
@@ -119,38 +123,41 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
}
left = state->inlen & 7;
-
- switch(left)
- {
- case 7: state->padding |= ((uint64_t) in[6]) << 48;
-
- case 6: state->padding |= ((uint64_t) in[5]) << 40;
-
- case 5: state->padding |= ((uint64_t) in[4]) << 32;
-
- case 4: state->padding |= ((uint64_t) in[3]) << 24;
-
- case 3: state->padding |= ((uint64_t) in[2]) << 16;
-
- case 2: state->padding |= ((uint64_t) in[1]) << 8;
-
- case 1: state->padding |= ((uint64_t) in[0]); break;
-
- case 0: break;
+ switch (left) {
+ case 7:
+ state->padding |= ((uint64_t) in[6]) << 48;
+ case 6:
+ state->padding |= ((uint64_t) in[5]) << 40;
+ case 5:
+ state->padding |= ((uint64_t) in[4]) << 32;
+ case 4:
+ state->padding |= ((uint64_t) in[3]) << 24;
+ case 3:
+ state->padding |= ((uint64_t) in[2]) << 16;
+ case 2:
+ state->padding |= ((uint64_t) in[1]) << 8;
+ case 1:
+ state->padding |= ((uint64_t) in[0]);
+ case 0:
+ break;
}
}
-void siphash24_finalize(uint8_t out[8], struct siphash *state) {
+uint64_t siphash24_finalize(struct siphash *state) {
uint64_t b;
- b = state->padding | (( ( uint64_t )state->inlen ) << 56);
+ assert(state);
+
+ b = state->padding | (((uint64_t) state->inlen) << 56);
+
#ifdef DEBUG
- printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0);
- printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1);
- printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2);
- printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3);
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
#endif
+
state->v3 ^= b;
sipround(state);
sipround(state);
@@ -169,14 +176,17 @@ void siphash24_finalize(uint8_t out[8], struct siphash *state) {
sipround(state);
sipround(state);
- *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3);
+ return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
}
-/* SipHash-2-4 */
-void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) {
+uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) {
struct siphash state;
+ assert(in);
+ assert(k);
+
siphash24_init(&state, k);
- siphash24_compress(_in, inlen, &state);
- siphash24_finalize(out, &state);
+ siphash24_compress(in, inlen, &state);
+
+ return siphash24_finalize(&state);
}
diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h
index 6c5cd98ee8..ba4f7d01b6 100644
--- a/src/basic/siphash24.h
+++ b/src/basic/siphash24.h
@@ -4,16 +4,16 @@
#include <sys/types.h>
struct siphash {
- uint64_t v0;
- uint64_t v1;
- uint64_t v2;
- uint64_t v3;
- uint64_t padding;
- size_t inlen;
+ uint64_t v0;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ uint64_t padding;
+ size_t inlen;
};
void siphash24_init(struct siphash *state, const uint8_t k[16]);
void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
-void siphash24_finalize(uint8_t out[8], struct siphash *state);
+uint64_t siphash24_finalize(struct siphash *state);
-void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]);
+uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]);
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index c60f2556af..129ffa811c 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
#include <sys/un.h>
#include <linux/netlink.h>
#include <linux/if_packet.h>
diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
index 909b220a24..fb92464274 100644
--- a/src/basic/stat-util.h
+++ b/src/basic/stat-util.h
@@ -52,9 +52,8 @@ int path_is_os_tree(const char *path);
int files_same(const char *filea, const char *fileb);
/* The .f_type field of struct statfs is really weird defined on
- * different archs. Let's use our own type we know is sufficiently
- * larger to store the possible values. */
-typedef long statfs_f_type_t;
+ * different archs. Let's give its type a name. */
+typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
int fd_check_fstype(int fd, statfs_f_type_t magic_value);
diff --git a/src/basic/strv.c b/src/basic/strv.c
index ba6df716a7..771781f9fc 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -27,8 +27,8 @@
#include "alloc-util.h"
#include "escape.h"
#include "string-util.h"
-#include "util.h"
#include "strv.h"
+#include "util.h"
char *strv_find(char **l, const char *name) {
char **i;
diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c
index 6542c0abf5..088ba53c29 100644
--- a/src/basic/strxcpyx.c
+++ b/src/basic/strxcpyx.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <string.h>
+
#include "strxcpyx.h"
size_t strpcpy(char **dest, size_t size, const char *src) {
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index f2185c1c11..b2c7a297ae 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include "macro.h"
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index b36fbe4f09..b9da6991da 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -27,6 +27,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
#include "strv.h"
@@ -323,15 +324,15 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
const char *suffix;
usec_t usec;
} table[] = {
- { "y", USEC_PER_YEAR },
- { "month", USEC_PER_MONTH },
- { "w", USEC_PER_WEEK },
- { "d", USEC_PER_DAY },
- { "h", USEC_PER_HOUR },
- { "min", USEC_PER_MINUTE },
- { "s", USEC_PER_SEC },
- { "ms", USEC_PER_MSEC },
- { "us", 1 },
+ { "y", USEC_PER_YEAR },
+ { "month", USEC_PER_MONTH },
+ { "w", USEC_PER_WEEK },
+ { "d", USEC_PER_DAY },
+ { "h", USEC_PER_HOUR },
+ { "min", USEC_PER_MINUTE },
+ { "s", USEC_PER_SEC },
+ { "ms", USEC_PER_MSEC },
+ { "us", 1 },
};
unsigned i;
@@ -658,29 +659,18 @@ int parse_timestamp(const char *t, usec_t *usec) {
parse_usec:
{
- char *end;
- unsigned long long val;
- size_t l;
+ unsigned add;
k++;
- if (*k < '0' || *k > '9')
+ r = parse_fractional_part_u(&k, 6, &add);
+ if (r < 0)
return -EINVAL;
- /* base 10 instead of base 0, .09 is not base 8 */
- errno = 0;
- val = strtoull(k, &end, 10);
- if (*end || errno)
+ if (*k)
return -EINVAL;
- l = end-k;
-
- /* val has l digits, make them 6 */
- for (; l < 6; l++)
- val *= 10;
- for (; l > 6; l--)
- val /= 10;
+ x_usec = add;
- x_usec = val;
}
from_tm:
@@ -711,33 +701,34 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
const char *suffix;
usec_t usec;
} table[] = {
- { "seconds", USEC_PER_SEC },
- { "second", USEC_PER_SEC },
- { "sec", USEC_PER_SEC },
- { "s", USEC_PER_SEC },
+ { "seconds", USEC_PER_SEC },
+ { "second", USEC_PER_SEC },
+ { "sec", USEC_PER_SEC },
+ { "s", USEC_PER_SEC },
{ "minutes", USEC_PER_MINUTE },
- { "minute", USEC_PER_MINUTE },
- { "min", USEC_PER_MINUTE },
- { "months", USEC_PER_MONTH },
- { "month", USEC_PER_MONTH },
- { "msec", USEC_PER_MSEC },
- { "ms", USEC_PER_MSEC },
- { "m", USEC_PER_MINUTE },
- { "hours", USEC_PER_HOUR },
- { "hour", USEC_PER_HOUR },
- { "hr", USEC_PER_HOUR },
- { "h", USEC_PER_HOUR },
- { "days", USEC_PER_DAY },
- { "day", USEC_PER_DAY },
- { "d", USEC_PER_DAY },
- { "weeks", USEC_PER_WEEK },
- { "week", USEC_PER_WEEK },
- { "w", USEC_PER_WEEK },
- { "years", USEC_PER_YEAR },
- { "year", USEC_PER_YEAR },
- { "y", USEC_PER_YEAR },
- { "usec", 1ULL },
- { "us", 1ULL },
+ { "minute", USEC_PER_MINUTE },
+ { "min", USEC_PER_MINUTE },
+ { "months", USEC_PER_MONTH },
+ { "month", USEC_PER_MONTH },
+ { "M", USEC_PER_MONTH },
+ { "msec", USEC_PER_MSEC },
+ { "ms", USEC_PER_MSEC },
+ { "m", USEC_PER_MINUTE },
+ { "hours", USEC_PER_HOUR },
+ { "hour", USEC_PER_HOUR },
+ { "hr", USEC_PER_HOUR },
+ { "h", USEC_PER_HOUR },
+ { "days", USEC_PER_DAY },
+ { "day", USEC_PER_DAY },
+ { "d", USEC_PER_DAY },
+ { "weeks", USEC_PER_WEEK },
+ { "week", USEC_PER_WEEK },
+ { "w", USEC_PER_WEEK },
+ { "years", USEC_PER_YEAR },
+ { "year", USEC_PER_YEAR },
+ { "y", USEC_PER_YEAR },
+ { "usec", 1ULL },
+ { "us", 1ULL },
};
const char *p, *s;
diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h
index d6181dd9a9..a8115eaa1f 100644
--- a/src/basic/unaligned.h
+++ b/src/basic/unaligned.h
@@ -21,8 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <endian.h>
#include <stdint.h>
+/* BE */
+
static inline uint16_t unaligned_read_be16(const void *_u) {
const uint8_t *u = _u;
@@ -64,3 +67,47 @@ static inline void unaligned_write_be64(void *_u, uint64_t a) {
unaligned_write_be32(u, (uint32_t) (a >> 32));
unaligned_write_be32(u + 4, (uint32_t) a);
}
+
+/* LE */
+
+static inline uint16_t unaligned_read_le16(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint16_t) u[1]) << 8) |
+ ((uint16_t) u[0]);
+}
+
+static inline uint32_t unaligned_read_le32(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint32_t) unaligned_read_le16(u + 2)) << 16) |
+ ((uint32_t) unaligned_read_le16(u));
+}
+
+static inline uint64_t unaligned_read_le64(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint64_t) unaligned_read_le32(u + 4)) << 32) |
+ ((uint64_t) unaligned_read_le32(u));
+}
+
+static inline void unaligned_write_le16(void *_u, uint16_t a) {
+ uint8_t *u = _u;
+
+ u[0] = (uint8_t) a;
+ u[1] = (uint8_t) (a >> 8);
+}
+
+static inline void unaligned_write_le32(void *_u, uint32_t a) {
+ uint8_t *u = _u;
+
+ unaligned_write_le16(u, (uint16_t) a);
+ unaligned_write_le16(u + 2, (uint16_t) (a >> 16));
+}
+
+static inline void unaligned_write_le64(void *_u, uint64_t a) {
+ uint8_t *u = _u;
+
+ unaligned_write_le32(u, (uint32_t) a);
+ unaligned_write_le32(u + 4, (uint32_t) (a >> 32));
+}
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index d6c936db37..397880b0b1 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <pwd.h>
#include <grp.h>
+#include <pwd.h>
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
index 11ff6674cf..6106e138be 100644
--- a/src/basic/user-util.h
+++ b/src/basic/user-util.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdbool.h>
+#include <sys/types.h>
bool uid_is_valid(uid_t uid);
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 7600d99903..b4063a4cec 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -44,10 +44,10 @@
*/
#include <errno.h>
-#include <stdlib.h>
#include <inttypes.h>
-#include <string.h>
#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include "alloc-util.h"
#include "hexdecoct.h"
diff --git a/src/basic/util.c b/src/basic/util.c
index 08bdcd28f2..58617b354a 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -73,6 +73,7 @@
#include "build.h"
#include "def.h"
#include "device-nodes.h"
+#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
#include "exit-status.h"
@@ -81,19 +82,20 @@
#include "formats-util.h"
#include "gunicode.h"
#include "hashmap.h"
+#include "hexdecoct.h"
#include "hostname-util.h"
#include "ioprio.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
-#include "hexdecoct.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "sparse-endian.h"
+#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
@@ -102,8 +104,6 @@
#include "utf8.h"
#include "util.h"
#include "virt.h"
-#include "dirent-util.h"
-#include "stat-util.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -206,7 +206,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) {
log_debug("Spawned %s as " PID_FMT ".", path, pid);
- r = hashmap_put(pids, UINT_TO_PTR(pid), path);
+ r = hashmap_put(pids, PID_TO_PTR(pid), path);
if (r < 0)
return log_oom();
path = NULL;
@@ -224,10 +224,10 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) {
_cleanup_free_ char *path = NULL;
pid_t pid;
- pid = PTR_TO_UINT(hashmap_first_key(pids));
+ pid = PTR_TO_PID(hashmap_first_key(pids));
assert(pid > 0);
- path = hashmap_remove(pids, UINT_TO_PTR(pid));
+ path = hashmap_remove(pids, PID_TO_PTR(pid));
assert(path);
wait_for_terminate_and_warn(path, pid, true);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index d088b7a804..b82680a54b 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -24,6 +24,8 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "fileio.h"
#include "process-util.h"
#include "stat-util.h"
@@ -267,13 +269,20 @@ int detect_vm(void) {
if (cached_found >= 0)
return cached_found;
- r = detect_vm_cpuid();
+ /* We have to use the correct order here:
+ * Some virtualization technologies do use KVM hypervisor but are
+ * expected to be detected as something else. So detect DMI first.
+ *
+ * An example is Virtualbox since version 5.0, which uses KVM backend.
+ * Detection via DMI works corretly, the CPU ID would find KVM
+ * only. */
+ r = detect_vm_dmi();
if (r < 0)
return r;
if (r != VIRTUALIZATION_NONE)
goto finish;
- r = detect_vm_dmi();
+ r = detect_vm_cpuid();
if (r < 0)
return r;
if (r != VIRTUALIZATION_NONE)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 38b79da886..6d35adc0e2 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -18,12 +18,12 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "console.h"
-#include "graphics.h"
-#include "pefile.h"
#include "disk.h"
+#include "graphics.h"
#include "linux.h"
+#include "pefile.h"
+#include "util.h"
#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index 66aa88f32e..2151d34432 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -18,8 +18,8 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "console.h"
+#include "util.h"
#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
{ 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c
index f732428216..efa91fa7ac 100644
--- a/src/boot/efi/graphics.c
+++ b/src/boot/efi/graphics.c
@@ -20,8 +20,8 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "graphics.h"
+#include "util.h"
EFI_STATUS graphics_mode(BOOLEAN on) {
#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
index 809c69310e..e9d097c132 100644
--- a/src/boot/efi/linux.c
+++ b/src/boot/efi/linux.c
@@ -17,8 +17,8 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "linux.h"
+#include "util.h"
#define SETUP_MAGIC 0x53726448 /* "HdrS" */
struct SetupHeader {
diff --git a/src/boot/efi/pefile.c b/src/boot/efi/pefile.c
index e6fedbc929..efb3271ee3 100644
--- a/src/boot/efi/pefile.c
+++ b/src/boot/efi/pefile.c
@@ -17,8 +17,8 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "pefile.h"
+#include "util.h"
struct DosFileHeader {
UINT8 Magic[2];
diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c
index 470ea3e2cc..b584b5e6a9 100644
--- a/src/boot/efi/splash.c
+++ b/src/boot/efi/splash.c
@@ -18,9 +18,9 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
#include "graphics.h"
#include "splash.h"
+#include "util.h"
struct bmp_file {
CHAR8 signature[2];
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 0c5ee4e9ff..2cd5c33cb6 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -16,12 +16,12 @@
#include <efi.h>
#include <efilib.h>
-#include "util.h"
-#include "pefile.h"
#include "disk.h"
#include "graphics.h"
-#include "splash.h"
#include "linux.h"
+#include "pefile.h"
+#include "splash.h"
+#include "util.h"
/* magic string to find in the binary image */
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####";
diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h
index bdb4b00199..8432a2a119 100644
--- a/src/bootchart/bootchart.h
+++ b/src/bootchart/bootchart.h
@@ -25,6 +25,7 @@
***/
#include <stdbool.h>
+
#include "list.h"
#define MAXCPUS 16
diff --git a/src/bootchart/store.h b/src/bootchart/store.h
index bbb4796efd..4d2e0d439f 100644
--- a/src/bootchart/store.h
+++ b/src/bootchart/store.h
@@ -25,6 +25,7 @@
***/
#include <dirent.h>
+
#include "bootchart.h"
double gettime_ns(void);
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index 05330c0577..2bf473ffc1 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -22,25 +22,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <string.h>
+#include <sys/utsname.h>
#include <time.h>
-#include <limits.h>
#include <unistd.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
#include "alloc-util.h"
#include "architecture.h"
-#include "util.h"
+#include "bootchart.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "list.h"
#include "macro.h"
#include "store.h"
#include "svg.h"
-#include "bootchart.h"
-#include "list.h"
#include "utf8.h"
-#include "fd-util.h"
+#include "util.h"
#define time_to_graph(t) ((t) * arg_scale_x)
#define ps_to_graph(n) ((n) * arg_scale_y)
diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c
index f0834e9525..debd58ce8b 100644
--- a/src/bus-proxyd/bus-xml-policy.c
+++ b/src/bus-proxyd/bus-xml-policy.c
@@ -392,11 +392,11 @@ static int file_load(Policy *p, const char *path) {
} else {
PolicyItem *first;
- first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
+ first = hashmap_get(p->user_items, UID_TO_PTR(i->uid));
item_append(i, &first);
i->uid_valid = true;
- r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
+ r = hashmap_replace(p->user_items, UID_TO_PTR(i->uid), first);
if (r < 0) {
LIST_REMOVE(items, first, i);
return log_oom();
@@ -424,11 +424,11 @@ static int file_load(Policy *p, const char *path) {
} else {
PolicyItem *first;
- first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
+ first = hashmap_get(p->group_items, GID_TO_PTR(i->gid));
item_append(i, &first);
i->gid_valid = true;
- r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
+ r = hashmap_replace(p->group_items, GID_TO_PTR(i->gid), first);
if (r < 0) {
LIST_REMOVE(items, first, i);
return log_oom();
@@ -787,7 +787,7 @@ static int policy_check(Policy *p, const struct policy_check_filter *filter) {
verdict = check_policy_items(p->default_items, filter);
if (filter->gid != GID_INVALID) {
- items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
+ items = hashmap_get(p->group_items, GID_TO_PTR(filter->gid));
if (items) {
v = check_policy_items(items, filter);
if (v != DUNNO)
@@ -796,7 +796,7 @@ static int policy_check(Policy *p, const struct policy_check_filter *filter) {
}
if (filter->uid != UID_INVALID) {
- items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
+ items = hashmap_get(p->user_items, UID_TO_PTR(filter->uid));
if (items) {
v = check_policy_items(items, filter);
if (v != DUNNO)
@@ -1155,7 +1155,7 @@ static void dump_hashmap_items(Hashmap *h) {
void *k;
HASHMAP_FOREACH_KEY(i, k, h, j) {
- printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
+ printf("\t%s Item for " UID_FMT ":\n", draw_special_char(DRAW_ARROW), PTR_TO_UID(k));
dump_items(i, "\t\t");
}
}
diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h
index 8f0ab8f17f..8dde0cb868 100644
--- a/src/bus-proxyd/bus-xml-policy.h
+++ b/src/bus-proxyd/bus-xml-policy.h
@@ -23,8 +23,8 @@
#include <pthread.h>
-#include "list.h"
#include "hashmap.h"
+#include "list.h"
typedef enum PolicyItemType {
_POLICY_ITEM_TYPE_UNSET = 0,
diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h
index da3834f8b0..9f68902441 100644
--- a/src/bus-proxyd/driver.h
+++ b/src/bus-proxyd/driver.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "bus-xml-policy.h"
#include "proxy.h"
diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c
index 6e47884209..2dc5fe631b 100644
--- a/src/bus-proxyd/stdio-bridge.c
+++ b/src/bus-proxyd/stdio-bridge.c
@@ -27,8 +27,8 @@
#include <string.h>
#include <unistd.h>
-#include "sd-daemon.h"
#include "sd-bus.h"
+#include "sd-daemon.h"
#include "alloc-util.h"
#include "bus-internal.h"
diff --git a/src/core/.gitignore b/src/core/.gitignore
index f293bbdc93..465b4fcc20 100644
--- a/src/core/.gitignore
+++ b/src/core/.gitignore
@@ -1,2 +1,3 @@
/macros.systemd
+/triggers.systemd
/systemd.pc
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index 3ae46d8cfb..0a484d89fc 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -21,16 +21,17 @@
#include <errno.h>
+
#include "audit-fd.h"
#ifdef HAVE_AUDIT
-#include <stdbool.h>
#include <libaudit.h>
+#include <stdbool.h>
+#include "fd-util.h"
#include "log.h"
#include "util.h"
-#include "fd-util.h"
static bool initialized = false;
static int audit_fd;
diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h
index 4a31f4c4be..f6c5f7c5af 100644
--- a/src/core/bus-endpoint.h
+++ b/src/core/bus-endpoint.h
@@ -24,8 +24,8 @@
typedef struct BusEndpoint BusEndpoint;
typedef struct BusEndpointPolicy BusEndpointPolicy;
-#include "hashmap.h"
#include "bus-policy.h"
+#include "hashmap.h"
struct BusEndpointPolicy {
char *name;
diff --git a/src/core/bus-policy.h b/src/core/bus-policy.h
index 3b04f5457a..2f61289185 100644
--- a/src/core/bus-policy.h
+++ b/src/core/bus-policy.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "kdbus.h"
#include "list.h"
#include "macro.h"
-#include "kdbus.h"
typedef struct BusNamePolicy BusNamePolicy;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index bed01fde21..d122175417 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -217,7 +217,7 @@ static int whitelist_device(const char *path, const char *node, const char *acc)
r = cg_set_attribute("devices", path, "devices.allow", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set devices.allow on %s: %m", path);
return r;
@@ -288,7 +288,7 @@ static int whitelist_major(const char *path, const char *name, char type, const
r = cg_set_attribute("devices", path, "devices.allow", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set devices.allow on %s: %m", path);
}
@@ -328,13 +328,13 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT);
r = cg_set_attribute("cpu", path, "cpu.shares", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.shares on %s: %m", path);
sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.cfs_period_us on %s: %m", path);
if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
@@ -343,7 +343,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
} else
r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.cfs_quota_us on %s: %m", path);
}
@@ -359,7 +359,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.weight on %s: %m", path);
/* FIXME: no way to reset this list */
@@ -373,7 +373,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight);
r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.weight_device on %s: %m", path);
}
}
@@ -392,7 +392,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
r = cg_set_attribute("blkio", path, a, buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set %s on %s: %m", a, path);
}
}
@@ -416,7 +416,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
}
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
}
@@ -432,7 +432,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
else
r = cg_set_attribute("devices", path, "devices.allow", "a");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to reset devices.list on %s: %m", path);
if (c->device_policy == CGROUP_CLOSED ||
@@ -494,7 +494,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
r = cg_set_attribute("pids", path, "pids.max", "max");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set pids.max on %s: %m", path);
}
@@ -505,7 +505,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
r = cg_set_attribute("net_cls", path, "net_cls.classid", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set net_cls.classid on %s: %m", path);
}
}
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 457544b49f..1b18d06652 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -112,8 +112,8 @@ struct CGroupContext {
bool delegate;
};
-#include "unit.h"
#include "cgroup-util.h"
+#include "unit.h"
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index 45f2c2ffd6..54830a515b 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -21,8 +21,8 @@
#include "automount.h"
#include "bus-util.h"
-#include "string-util.h"
#include "dbus-automount.h"
+#include "string-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
index 05ac89c3c0..445b237643 100644
--- a/src/core/dbus-busname.c
+++ b/src/core/dbus-busname.c
@@ -21,9 +21,9 @@
#include "bus-util.h"
#include "busname.h"
+#include "dbus-busname.h"
#include "string-util.h"
#include "unit.h"
-#include "dbus-busname.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
index cb156fd37c..97e4a47556 100644
--- a/src/core/dbus-device.c
+++ b/src/core/dbus-device.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "device.h"
#include "dbus-device.h"
+#include "device.h"
+#include "unit.h"
const sd_bus_vtable bus_device_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index 3b8116281c..c633eb1b76 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -19,11 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "signal-util.h"
#include "bus-util.h"
-
-#include "kill.h"
#include "dbus-kill.h"
+#include "kill.h"
+#include "signal-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
index 794c402048..1d32fca547 100644
--- a/src/core/dbus-kill.h
+++ b/src/core/dbus-kill.h
@@ -23,8 +23,8 @@
#include "sd-bus.h"
-#include "unit.h"
#include "kill.h"
+#include "unit.h"
extern const sd_bus_vtable bus_kill_vtable[];
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index f58ac55009..2562396180 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -648,6 +648,7 @@ static int transient_unit_from_message(
Unit **unit,
sd_bus_error *error) {
+ UnitType t;
Unit *u;
int r;
@@ -655,12 +656,18 @@ static int transient_unit_from_message(
assert(message);
assert(name);
+ t = unit_name_to_type(name);
+ if (t < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type.");
+
+ if (!unit_vtable[t]->can_transient)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
+
r = manager_load_unit(m, name, NULL, error, &u);
if (r < 0)
return r;
- if (u->load_state != UNIT_NOT_FOUND ||
- set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
+ if (!unit_is_pristine(u))
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
/* OK, the unit failed to load and is unreferenced, now let's
@@ -674,6 +681,9 @@ static int transient_unit_from_message(
if (r < 0)
return r;
+ /* Now load the missing bits of the unit we just created */
+ manager_dispatch_load_queue(m);
+
*unit = u;
return 0;
@@ -684,8 +694,6 @@ static int transient_aux_units_from_message(
sd_bus_message *message,
sd_bus_error *error) {
- Unit *u;
- char *name = NULL;
int r;
assert(m);
@@ -696,20 +704,17 @@ static int transient_aux_units_from_message(
return r;
while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
+ const char *name = NULL;
+ Unit *u;
+
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
r = transient_unit_from_message(m, message, name, &u, error);
- if (r < 0 && r != -EEXIST)
+ if (r < 0)
return r;
- if (r != -EEXIST) {
- r = unit_load(u);
- if (r < 0)
- return r;
- }
-
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
@@ -728,7 +733,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
const char *name, *smode;
Manager *m = userdata;
JobMode mode;
- UnitType t;
Unit *u;
int r;
@@ -743,13 +747,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- t = unit_name_to_type(name);
- if (t < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
-
- if (!unit_vtable[t]->can_transient)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
-
mode = job_mode_from_string(smode);
if (mode < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
@@ -768,13 +765,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- /* And load this stub fully */
- r = unit_load(u);
- if (r < 0)
- return r;
-
- manager_dispatch_load_queue(m);
-
/* Finally, start it */
return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
}
@@ -1964,6 +1954,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 90a6d37073..bc5751a10d 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -23,10 +23,10 @@
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
+#include "dbus-mount.h"
#include "mount.h"
#include "string-util.h"
#include "unit.h"
-#include "dbus-mount.h"
static int property_get_what(
sd_bus *bus,
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index 9e32b5fb06..e0544e9161 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -20,10 +20,10 @@
***/
#include "bus-util.h"
+#include "dbus-path.h"
#include "path.h"
#include "string-util.h"
#include "unit.h"
-#include "dbus-path.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult);
diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h
index 33beda47b7..4fb0b25e09 100644
--- a/src/core/dbus-scope.h
+++ b/src/core/dbus-scope.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_scope_vtable[];
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
index aab9f7aa26..a67b64ab5b 100644
--- a/src/core/dbus-service.h
+++ b/src/core/dbus-service.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_service_vtable[];
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
index 09e78d1f33..469e3e1c93 100644
--- a/src/core/dbus-slice.c
+++ b/src/core/dbus-slice.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "slice.h"
#include "dbus-cgroup.h"
#include "dbus-slice.h"
+#include "slice.h"
+#include "unit.h"
const sd_bus_vtable bus_slice_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h
index eadc3b1a9c..117d11471b 100644
--- a/src/core/dbus-slice.h
+++ b/src/core/dbus-slice.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_slice_vtable[];
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index be5ef261a6..895dd07753 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -150,6 +150,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
+ SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
index 17164d9871..8dad6ea2e9 100644
--- a/src/core/dbus-socket.h
+++ b/src/core/dbus-socket.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_socket_vtable[];
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 603ca95fd9..f2a0f1d172 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -23,10 +23,10 @@
#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
+#include "dbus-swap.h"
#include "string-util.h"
#include "swap.h"
#include "unit.h"
-#include "dbus-swap.h"
static int property_get_priority(
sd_bus *bus,
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
index 9469f68ab8..a414ca7f75 100644
--- a/src/core/dbus-swap.h
+++ b/src/core/dbus-swap.h
@@ -23,6 +23,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_swap_vtable[];
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
index 350f5c3ed2..654bcf1a29 100644
--- a/src/core/dbus-target.c
+++ b/src/core/dbus-target.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
#include "dbus-target.h"
+#include "unit.h"
const sd_bus_vtable bus_target_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index a8a280d961..ec301df6d7 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -180,8 +180,10 @@ const sd_bus_vtable bus_timer_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
@@ -282,8 +284,23 @@ static int bus_timer_set_transient_property(
return 1;
- } else if (streq(name, "WakeSystem")) {
+ } else if (streq(name, "RandomizedDelayUSec")) {
+ usec_t u = 0;
+
+ r = sd_bus_message_read(message, "t", &u);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ char time[FORMAT_TIMESPAN_MAX];
+
+ t->random_usec = u;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ }
+
+ return 1;
+ } else if (streq(name, "WakeSystem")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -292,11 +309,24 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
t->wake_system = b;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
}
return 1;
+ } else if (streq(name, "RemainAfterElapse")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ t->remain_after_elapse = b;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
+ }
+
+ return 1;
}
return 0;
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
index 103172f055..ca35c4b8c1 100644
--- a/src/core/dbus-timer.h
+++ b/src/core/dbus-timer.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_timer_vtable[];
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index 0d7e5f8d83..ac9ee2d6b8 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_unit_vtable[];
diff --git a/src/core/execute.c b/src/core/execute.c
index 07979bf8b3..677480cbe1 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2414,8 +2414,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i])
- fprintf(f, "%s%s: "RLIM_FMT"\n",
- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
+ fprintf(f, "%s%s: " RLIM_FMT " " RLIM_FMT "\n",
+ prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur, c->rlimit[i]->rlim_max);
if (c->ioprio_set) {
_cleanup_free_ char *class_str = NULL;
diff --git a/src/core/execute.h b/src/core/execute.h
index 1faff160cb..be5be9f531 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -27,16 +27,16 @@ typedef struct ExecContext ExecContext;
typedef struct ExecRuntime ExecRuntime;
typedef struct ExecParameters ExecParameters;
-#include <sys/capability.h>
+#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
-#include <sched.h>
+#include <sys/capability.h>
-#include "list.h"
+#include "bus-endpoint.h"
#include "fdset.h"
+#include "list.h"
#include "missing.h"
#include "namespace.h"
-#include "bus-endpoint.h"
typedef enum ExecUtmpMode {
EXEC_UTMP_INIT,
@@ -204,8 +204,8 @@ struct ExecContext {
BusEndpoint *bus_endpoint;
};
-#include "cgroup.h"
#include "cgroup-util.h"
+#include "cgroup.h"
struct ExecParameters {
char **argv;
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 3645f9c515..d92a9a764f 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -25,12 +25,12 @@
#include "alloc-util.h"
#include "fileio.h"
+#include "hostname-setup.h"
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
#include "util.h"
-#include "hostname-setup.h"
int hostname_setup(void) {
int r;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 9572fa17d9..4f42ae6f31 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
+#include <unistd.h>
#include "fd-util.h"
#include "fileio.h"
diff --git a/src/core/job.c b/src/core/job.c
index 53e0947215..9654590635 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -500,17 +500,26 @@ static void job_change_type(Job *j, JobType newtype) {
}
static int job_perform_on_unit(Job **j) {
- /* While we execute this operation the job might go away (for
- * example: because it finishes immediately or is replaced by a new,
- * conflicting job.) To make sure we don't access a freed job later on
- * we store the id here, so that we can verify the job is still
- * valid. */
- Manager *m = (*j)->manager;
- Unit *u = (*j)->unit;
- JobType t = (*j)->type;
- uint32_t id = (*j)->id;
+ uint32_t id;
+ Manager *m;
+ JobType t;
+ Unit *u;
int r;
+ /* While we execute this operation the job might go away (for
+ * example: because it finishes immediately or is replaced by
+ * a new, conflicting job.) To make sure we don't access a
+ * freed job later on we store the id here, so that we can
+ * verify the job is still valid. */
+
+ assert(j);
+ assert(*j);
+
+ m = (*j)->manager;
+ u = (*j)->unit;
+ t = (*j)->type;
+ id = (*j)->id;
+
switch (t) {
case JOB_START:
r = unit_start(u);
@@ -518,6 +527,7 @@ static int job_perform_on_unit(Job **j) {
case JOB_RESTART:
t = JOB_STOP;
+ /* fall through */
case JOB_STOP:
r = unit_stop(u);
break;
@@ -617,8 +627,7 @@ int job_run_and_invalidate(Job *j) {
}
_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
- const char *format;
- const UnitStatusMessageFormats *format_table;
+
static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Started %s.",
[JOB_TIMEOUT] = "Timed out starting %s.",
@@ -644,11 +653,14 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
[JOB_SKIPPED] = "%s is not active.",
};
+ const UnitStatusMessageFormats *format_table;
+ const char *format;
+
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
- if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) {
+ if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) {
format_table = &UNIT_VTABLE(u)->status_message_formats;
if (format_table) {
format = t == JOB_START ? format_table->finished_start_job[result] :
@@ -672,7 +684,6 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
}
static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
[JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL,
[JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL,
@@ -683,10 +694,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
[JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL,
};
+ const char *format;
+
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
+ /* Reload status messages have traditionally not been printed to console. */
+ if (t == JOB_RELOAD)
+ return;
+
format = job_get_status_message_format(u, t, result);
if (!format)
return;
@@ -699,10 +716,10 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
REENABLE_WARNING;
if (t == JOB_START && result == JOB_FAILED) {
- _cleanup_free_ char *quoted = shell_maybe_quote(u->id);
+ _cleanup_free_ char *quoted;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
- "See 'systemctl status %s' for details.", strna(quoted));
+ quoted = shell_maybe_quote(u->id);
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
}
}
@@ -740,13 +757,22 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
snprintf(buf, sizeof(buf), format, unit_description(u));
REENABLE_WARNING;
- if (t == JOB_START)
+ switch (t) {
+
+ case JOB_START:
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- else if (t == JOB_STOP || t == JOB_RESTART)
- mid = SD_MESSAGE_UNIT_STOPPED;
- else if (t == JOB_RELOAD)
+ break;
+
+ case JOB_RELOAD:
mid = SD_MESSAGE_UNIT_RELOADED;
- else {
+ break;
+
+ case JOB_STOP:
+ case JOB_RESTART:
+ mid = SD_MESSAGE_UNIT_STOPPED;
+ break;
+
+ default:
log_struct(job_result_log_level[result],
LOG_UNIT_ID(u),
LOG_MESSAGE("%s", buf),
@@ -770,10 +796,7 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
return;
job_log_status_message(u, t, result);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (t != JOB_RELOAD)
- job_print_status_message(u, t, result);
+ job_print_status_message(u, t, result);
}
static void job_fail_dependencies(Unit *u, UnitDependency d) {
diff --git a/src/core/job.h b/src/core/job.h
index 60d8bd4f3e..118b24e5b7 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -26,6 +26,7 @@
#include "sd-event.h"
#include "list.h"
+#include "unit-name.h"
typedef struct Job Job;
typedef struct JobDependency JobDependency;
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 651f79a1fe..a6ab8cf4b3 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -19,17 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <string.h>
+#include <unistd.h>
#ifdef HAVE_KMOD
#include <libkmod.h>
#endif
-#include "macro.h"
-#include "capability-util.h"
#include "bus-util.h"
+#include "capability-util.h"
#include "kmod-setup.h"
+#include "macro.h"
#ifdef HAVE_KMOD
static void systemd_kmod_log(
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 11566af51b..3fa66f91aa 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -20,13 +20,13 @@
***/
-#include "unit.h"
+#include "conf-parser.h"
#include "load-dropin.h"
+#include "load-fragment.h"
#include "log.h"
#include "strv.h"
#include "unit-name.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
+#include "unit.h"
static int add_dependency_consumer(
UnitDependency dependency,
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
index 1e018c4525..93ffcc4a72 100644
--- a/src/core/load-dropin.h
+++ b/src/core/load-dropin.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
#include "dropin.h"
+#include "unit.h"
/* Read service data supplementary drop-in directories */
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 4c5376d601..0408b9a829 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -126,7 +126,7 @@ $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0,
$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)
+$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
$1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)'
)m4_dnl
@@ -249,6 +249,7 @@ Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCK
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, 0
Socket.BindIPv6Only, config_parse_socket_bind, 0, 0,
Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog)
Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0
@@ -344,7 +345,9 @@ Timer.OnUnitActiveSec, config_parse_timer, 0,
Timer.OnUnitInactiveSec, config_parse_timer, 0, 0
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
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 62cad0a0c0..3c124495b6 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -32,8 +32,8 @@
#include <sys/resource.h>
#include <sys/stat.h>
-#include "alloc-util.h"
#include "af-list.h"
+#include "alloc-util.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
@@ -421,6 +421,37 @@ int config_parse_socket_listen(const char *unit,
return 0;
}
+int config_parse_socket_protocol(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Socket *s;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ s = SOCKET(data);
+
+ if (streq(rvalue, "udplite"))
+ s->socket_protocol = IPPROTO_UDPLITE;
+ else if (streq(rvalue, "sctp"))
+ s->socket_protocol = IPPROTO_SCTP;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
int config_parse_socket_bind(const char *unit,
const char *filename,
unsigned line,
@@ -1058,59 +1089,123 @@ int config_parse_bounding_set(
return 0;
}
-int config_parse_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) {
+static int rlim_parse_u64(const char *val, rlim_t *res) {
+ int r = 0;
- struct rlimit **rl = data;
- rlim_t v;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- rl += ltype;
-
- if (streq(rvalue, "infinity"))
- v = RLIM_INFINITY;
+ if (streq(val, "infinity"))
+ *res = RLIM_INFINITY;
else {
uint64_t u;
/* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
- r = safe_atou64(rvalue, &u);
+ r = safe_atou64(val, &u);
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
r = -ERANGE;
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
+ if (r == 0)
+ *res = (rlim_t) u;
+ }
+ return r;
+}
+
+static int rlim_parse_size(const char *val, rlim_t *res) {
+ int r = 0;
+
+ if (streq(val, "infinity"))
+ *res = RLIM_INFINITY;
+ else {
+ uint64_t u;
+
+ r = parse_size(val, 1024, &u);
+ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+ r = -ERANGE;
+ if (r == 0)
+ *res = (rlim_t) u;
+ }
+ return r;
+}
+
+static int rlim_parse_sec(const char *val, rlim_t *res) {
+ int r = 0;
+
+ if (streq(val, "infinity"))
+ *res = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_sec(val, &t);
+ if (r < 0)
+ return r;
+ if (t == USEC_INFINITY)
+ *res = RLIM_INFINITY;
+ else
+ *res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
- v = (rlim_t) u;
}
+ return r;
+}
+
+static int rlim_parse_usec(const char *val, rlim_t *res) {
+ int r = 0;
+
+ if (streq(val, "infinity"))
+ *res = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_time(val, &t, 1);
+ if (r < 0)
+ return r;
+ if (t == USEC_INFINITY)
+ *res = RLIM_INFINITY;
+ else
+ *res = (rlim_t) t;
+ }
+ return r;
+}
+
+static int parse_rlimit_range(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *value,
+ struct rlimit **rl,
+ int (*rlim_parser)(const char *, rlim_t *)) {
+
+ const char *whole_value = value;
+ rlim_t soft, hard;
+ _cleanup_free_ char *sword = NULL, *hword = NULL;
+ int nwords, r;
+
+ assert(value);
+
+ /* <value> or <soft:hard> */
+ nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL);
+ r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0;
+
+ if (r == 0)
+ r = rlim_parser(sword, &soft);
+ if (r == 0 && nwords == 2)
+ r = rlim_parser(hword, &hard);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value);
+ return 0;
+ }
+ if (nwords == 2 && soft > hard)
+ return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value);
if (!*rl) {
*rl = new(struct rlimit, 1);
if (!*rl)
return log_oom();
}
-
- (*rl)->rlim_cur = (*rl)->rlim_max = v;
+ (*rl)->rlim_cur = soft;
+ (*rl)->rlim_max = nwords == 2 ? hard : soft;
return 0;
}
-int config_parse_bytes_limit(
+int config_parse_limit(
const char *unit,
const char *filename,
unsigned line,
@@ -1123,8 +1218,6 @@ int config_parse_bytes_limit(
void *userdata) {
struct rlimit **rl = data;
- rlim_t bytes;
- int r;
assert(filename);
assert(lvalue);
@@ -1132,31 +1225,30 @@ int config_parse_bytes_limit(
assert(data);
rl += ltype;
+ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64);
+}
- if (streq(rvalue, "infinity"))
- bytes = RLIM_INFINITY;
- else {
- uint64_t u;
-
- r = parse_size(rvalue, 1024, &u);
- if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
- r = -ERANGE;
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
+int config_parse_bytes_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) {
- bytes = (rlim_t) u;
- }
+ struct rlimit **rl = data;
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
- return log_oom();
- }
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
- (*rl)->rlim_cur = (*rl)->rlim_max = bytes;
- return 0;
+ rl += ltype;
+ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size);
}
int config_parse_sec_limit(
@@ -1172,8 +1264,6 @@ int config_parse_sec_limit(
void *userdata) {
struct rlimit **rl = data;
- rlim_t seconds;
- int r;
assert(filename);
assert(lvalue);
@@ -1181,35 +1271,9 @@ int config_parse_sec_limit(
assert(data);
rl += ltype;
-
- if (streq(rvalue, "infinity"))
- seconds = RLIM_INFINITY;
- else {
- usec_t t;
-
- r = parse_sec(rvalue, &t);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (t == USEC_INFINITY)
- seconds = RLIM_INFINITY;
- else
- seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
- }
-
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
- return log_oom();
- }
-
- (*rl)->rlim_cur = (*rl)->rlim_max = seconds;
- return 0;
+ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec);
}
-
int config_parse_usec_limit(
const char *unit,
const char *filename,
@@ -1223,8 +1287,6 @@ int config_parse_usec_limit(
void *userdata) {
struct rlimit **rl = data;
- rlim_t useconds;
- int r;
assert(filename);
assert(lvalue);
@@ -1232,33 +1294,10 @@ int config_parse_usec_limit(
assert(data);
rl += ltype;
+ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
+}
- if (streq(rvalue, "infinity"))
- useconds = RLIM_INFINITY;
- else {
- usec_t t;
-
- r = parse_time(rvalue, &t, 1);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
- if (t == USEC_INFINITY)
- useconds = RLIM_INFINITY;
- else
- useconds = (rlim_t) t;
- }
-
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
- return log_oom();
- }
-
- (*rl)->rlim_cur = (*rl)->rlim_max = useconds;
- return 0;
-}
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
@@ -1305,38 +1344,28 @@ int config_parse_exec_mount_flags(const char *unit,
void *data,
void *userdata) {
- ExecContext *c = data;
- const char *word, *state;
- size_t l;
+
unsigned long flags = 0;
+ ExecContext *c = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
- _cleanup_free_ char *t;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- if (streq(t, "shared"))
- flags = MS_SHARED;
- else if (streq(t, "slave"))
- flags = MS_SLAVE;
- else if (streq(t, "private"))
- flags = MS_PRIVATE;
- else {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
- return 0;
- }
+ if (streq(rvalue, "shared"))
+ flags = MS_SHARED;
+ else if (streq(rvalue, "slave"))
+ flags = MS_SLAVE;
+ else if (streq(rvalue, "private"))
+ flags = MS_PRIVATE;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
+ return 0;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
c->mount_flags = flags;
+
return 0;
}
@@ -2991,12 +3020,11 @@ int config_parse_tasks_max(
void *data,
void *userdata) {
- CGroupContext *c = data;
- uint64_t u;
+ uint64_t *tasks_max = data, u;
int r;
if (isempty(rvalue) || streq(rvalue, "infinity")) {
- c->tasks_max = (uint64_t) -1;
+ *tasks_max = (uint64_t) -1;
return 0;
}
@@ -3006,7 +3034,7 @@ int config_parse_tasks_max(
return 0;
}
- c->tasks_max = u;
+ *tasks_max = u;
return 0;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 62300c10f9..a451fc164a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -38,6 +38,7 @@ int config_parse_unit_path_printf(const char *unit, const char *filename, unsign
int config_parse_unit_path_strv_printf(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_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_protocol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_nice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index bd632131b9..4c8d920389 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -24,12 +24,12 @@
#include "env-util.h"
#include "fileio.h"
+#include "locale-setup.h"
#include "locale-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
#include "virt.h"
-#include "locale-setup.h"
int locale_setup(char ***environment) {
char **add;
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index bea6ef1da3..2cace3d3ba 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -1,4 +1,4 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*- */
+# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
#
# This file is part of systemd.
#
@@ -39,17 +39,16 @@ Requires(postun): systemd \
%systemd_post() \
if [ $1 -eq 1 ] ; then \
# Initial installation \
- systemctl preset %{?*} >/dev/null 2>&1 || : \
+ systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \
fi \
%{nil}
-%systemd_user_post() %systemd_post --user --global %{?*}
+%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}}
%systemd_preun() \
if [ $1 -eq 0 ] ; then \
# Package removal, not upgrade \
- systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \
- systemctl stop %{?*} > /dev/null 2>&1 || : \
+ systemctl --no-reload disable --now %{?*} > /dev/null 2>&1 || : \
fi \
%{nil}
@@ -60,14 +59,11 @@ if [ $1 -eq 0 ] ; then \
fi \
%{nil}
-%systemd_postun() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
-%{nil}
+%systemd_postun() %{nil}
%systemd_user_postun() %{nil}
%systemd_postun_with_restart() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
if [ $1 -ge 1 ] ; then \
# Package upgrade, not uninstall \
systemctl try-restart %{?*} >/dev/null 2>&1 || : \
diff --git a/src/core/main.c b/src/core/main.c
index 33529c3e76..97f904b031 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -37,8 +37,8 @@
#include <valgrind/valgrind.h>
#endif
-#include "sd-daemon.h"
#include "sd-bus.h"
+#include "sd-daemon.h"
#include "alloc-util.h"
#include "architecture.h"
@@ -125,7 +125,8 @@ static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
-static bool arg_default_tasks_accounting = false;
+static bool arg_default_tasks_accounting = true;
+static uint64_t arg_default_tasks_max = UINT64_C(512);
static void pager_open_if_enabled(void) {
@@ -657,7 +658,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
- { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
+ { "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
{ "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
{ "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
{ "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
@@ -672,11 +673,12 @@ static int parse_config_file(void) {
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
{ "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
+ { "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
+ { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max },
{}
};
@@ -712,6 +714,7 @@ static void manager_set_defaults(Manager *m) {
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
+ m->default_tasks_max = arg_default_tasks_max;
manager_set_default_rlimits(m, arg_default_rlimit);
manager_environment_add(m, NULL, arg_default_environment);
diff --git a/src/core/manager.c b/src/core/manager.c
index f695b8a66c..edff6758c5 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -577,6 +577,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->running_as = running_as;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
+ m->default_tasks_accounting = true;
+ m->default_tasks_max = UINT64_C(512);
/* Prepare log fields we can use for structured logging */
m->unit_log_field = unit_log_fields[running_as];
diff --git a/src/core/manager.h b/src/core/manager.h
index bc3f02f872..f6903a5c34 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -21,12 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <libmount.h>
#include <stdbool.h>
#include <stdio.h>
-#include <libmount.h>
#include "sd-bus.h"
#include "sd-event.h"
+
#include "cgroup-util.h"
#include "fdset.h"
#include "hashmap.h"
@@ -260,6 +261,7 @@ struct Manager {
bool default_blockio_accounting;
bool default_tasks_accounting;
+ uint64_t default_tasks_max;
usec_t default_timer_accuracy_usec;
struct rlimit *rlimit[_RLIMIT_MAX];
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index b2596d1cd1..2b8d590ed1 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -19,11 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mount.h>
#include <errno.h>
+#include <ftw.h>
#include <stdlib.h>
+#include <sys/mount.h>
#include <unistd.h>
-#include <ftw.h>
#include "alloc-util.h"
#include "bus-util.h"
diff --git a/src/core/mount.h b/src/core/mount.h
index 83d14ae713..9f78aa9075 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -23,8 +23,8 @@
typedef struct Mount Mount;
-#include "kill.h"
#include "execute.h"
+#include "kill.h"
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
diff --git a/src/core/scope.c b/src/core/scope.c
index 5f6527c155..1953af1f88 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -402,15 +402,10 @@ static bool scope_check_gc(Unit *u) {
/* Never clean up scopes that still have a process around,
* even if the scope is formally dead. */
- if (u->cgroup_path) {
- int r;
+ if (!u->cgroup_path)
+ return false;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
- if (r <= 0)
- return true;
- }
-
- return false;
+ return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0;
}
static void scope_notify_cgroup_empty_event(Unit *u) {
@@ -577,6 +572,7 @@ const UnitVTable scope_vtable = {
.no_alias = true,
.no_instances = true,
+ .can_transient = true,
.init = scope_init,
.load = scope_load,
@@ -611,7 +607,5 @@ const UnitVTable scope_vtable = {
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
- .can_transient = true,
-
.enumerate = scope_enumerate,
};
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 4bcdd27389..8856927c88 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -23,10 +23,10 @@
#ifdef HAVE_SELINUX
-#include <stdio.h>
#include <errno.h>
-#include <selinux/selinux.h>
#include <selinux/avc.h>
+#include <selinux/selinux.h>
+#include <stdio.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
#endif
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index 30725521cb..3566ba529f 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "bus-util.h"
#include "manager.h"
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index d9b00fb95c..d4757e0853 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -29,10 +29,10 @@
#include "log.h"
#include "macro.h"
+#include "selinux-setup.h"
#include "selinux-util.h"
#include "string-util.h"
#include "util.h"
-#include "selinux-setup.h"
#ifdef HAVE_SELINUX
_printf_(2,3)
diff --git a/src/core/service.h b/src/core/service.h
index e765668247..d0faad88e0 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -24,10 +24,10 @@
typedef struct Service Service;
typedef struct ServiceFDStore ServiceFDStore;
+#include "exit-status.h"
+#include "kill.h"
#include "path.h"
#include "ratelimit.h"
-#include "kill.h"
-#include "exit-status.h"
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
diff --git a/src/core/slice.c b/src/core/slice.c
index 39dabae055..06ac6f8450 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -24,12 +24,12 @@
#include "alloc-util.h"
#include "dbus-slice.h"
#include "log.h"
+#include "slice.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit.h"
-#include "slice.h"
static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_DEAD] = UNIT_INACTIVE,
@@ -305,6 +305,7 @@ const UnitVTable slice_vtable = {
.no_alias = true,
.no_instances = true,
+ .can_transient = true,
.load = slice_load,
diff --git a/src/core/socket.c b/src/core/socket.c
index 5b9e32ce9d..687675b24e 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1266,6 +1266,19 @@ static int socket_open_fds(Socket *s) {
know_label = true;
}
+ /* Apply the socket protocol */
+ switch(p->address.type) {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ if (p->socket->socket_protocol == IPPROTO_SCTP)
+ p->address.protocol = p->socket->socket_protocol;
+ break;
+ case SOCK_DGRAM:
+ if (p->socket->socket_protocol == IPPROTO_UDPLITE)
+ p->address.protocol = p->socket->socket_protocol;
+ break;
+ }
+
r = socket_address_listen(
&p->address,
SOCK_CLOEXEC|SOCK_NONBLOCK,
diff --git a/src/core/socket.h b/src/core/socket.h
index 94cda8a90d..08033287a6 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -23,9 +23,9 @@
typedef struct Socket Socket;
-#include "socket-util.h"
#include "mount.h"
#include "service.h"
+#include "socket-util.h"
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
@@ -120,6 +120,8 @@ struct Socket {
bool remove_on_stop;
bool writable;
+ int socket_protocol;
+
/* Socket options */
bool keep_alive;
bool no_delay;
diff --git a/src/core/swap.c b/src/core/swap.c
index ee0838e676..b6e4372fc0 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -211,6 +211,8 @@ static int swap_add_device_links(Swap *s) {
}
static int swap_add_default_dependencies(Swap *s) {
+ int r;
+
assert(s);
if (!UNIT(s)->default_dependencies)
@@ -222,6 +224,12 @@ static int swap_add_default_dependencies(Swap *s) {
if (detect_container() > 0)
return 0;
+ /* swap units generated for the swap dev links are missing the
+ * ordering dep against the swap target. */
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
+ if (r < 0)
+ return r;
+
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
}
diff --git a/src/core/system.conf b/src/core/system.conf
index 50668e12c4..e2ded27333 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -40,7 +40,8 @@
#DefaultCPUAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
-#DefaultTasksAccounting=no
+#DefaultTasksAccounting=yes
+#DefaultTasksMax=512
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=
diff --git a/src/core/timer.c b/src/core/timer.c
index 51b1d875be..6b0f8e8616 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -27,6 +27,7 @@
#include "dbus-timer.h"
#include "fs-util.h"
#include "parse-util.h"
+#include "random-util.h"
#include "special.h"
#include "string-table.h"
#include "string-util.h"
@@ -55,6 +56,7 @@ static void timer_init(Unit *u) {
t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
t->next_elapse_realtime = USEC_INFINITY;
t->accuracy_usec = u->manager->default_timer_accuracy_usec;
+ t->remain_after_elapse = true;
}
void timer_free_values(Timer *t) {
@@ -217,13 +219,15 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
"%sUnit: %s\n"
"%sPersistent: %s\n"
"%sWakeSystem: %s\n"
- "%sAccuracy: %s\n",
+ "%sAccuracy: %s\n"
+ "%sRemainAfterElapse: %s\n",
prefix, timer_state_to_string(t->state),
prefix, timer_result_to_string(t->result),
prefix, trigger ? trigger->id : "n/a",
prefix, yes_no(t->persistent),
prefix, yes_no(t->wake_system),
- prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
+ prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
+ prefix, yes_no(t->remain_after_elapse));
LIST_FOREACH(value, v, t->values) {
@@ -275,13 +279,13 @@ static int timer_coldplug(Unit *u) {
assert(t);
assert(t->state == TIMER_DEAD);
- if (t->deserialized_state != t->state) {
+ if (t->deserialized_state == t->state)
+ return 0;
- if (t->deserialized_state == TIMER_WAITING)
- timer_enter_waiting(t, false);
- else
- timer_set_state(t, t->deserialized_state);
- }
+ if (t->deserialized_state == TIMER_WAITING)
+ timer_enter_waiting(t, false);
+ else
+ timer_set_state(t, t->deserialized_state);
return 0;
}
@@ -295,6 +299,23 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
}
+static void timer_enter_elapsed(Timer *t, bool leave_around) {
+ assert(t);
+
+ /* If a unit is marked with RemainAfterElapse=yes we leave it
+ * around even after it elapsed once, so that starting it
+ * later again does not necessarily mean immediate
+ * retriggering. We unconditionally leave units with
+ * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
+ * since they might be restarted automatically at any time
+ * later on. */
+
+ if (t->remain_after_elapse || leave_around)
+ timer_set_state(t, TIMER_ELAPSED);
+ else
+ timer_enter_dead(t, TIMER_SUCCESS);
+}
+
static usec_t monotonic_to_boottime(usec_t t) {
usec_t a, b;
@@ -310,10 +331,33 @@ static usec_t monotonic_to_boottime(usec_t t) {
return 0;
}
+static void add_random(Timer *t, usec_t *v) {
+ char s[FORMAT_TIMESPAN_MAX];
+ usec_t add;
+
+ assert(t);
+ assert(*v);
+
+ if (t->random_usec == 0)
+ return;
+ if (*v == USEC_INFINITY)
+ return;
+
+ add = random_u64() % t->random_usec;
+
+ if (*v + add < *v) /* overflow */
+ *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
+ else
+ *v += add;
+
+ log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
+}
+
static void timer_enter_waiting(Timer *t, bool initial) {
bool found_monotonic = false, found_realtime = false;
usec_t ts_realtime, ts_monotonic;
usec_t base = 0;
+ bool leave_around = false;
TimerValue *v;
int r;
@@ -374,7 +418,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_UNIT_ACTIVE:
-
+ leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
if (base <= 0)
@@ -386,7 +430,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_UNIT_INACTIVE:
-
+ leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
if (base <= 0)
@@ -423,14 +467,18 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (!found_monotonic && !found_realtime) {
log_unit_debug(UNIT(t), "Timer is elapsed.");
- timer_set_state(t, TIMER_ELAPSED);
+ timer_enter_elapsed(t, leave_around);
return;
}
if (found_monotonic) {
char buf[FORMAT_TIMESPAN_MAX];
+ usec_t left;
- log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
+ add_random(t, &t->next_elapse_monotonic_or_boottime);
+
+ left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0;
+ log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
if (t->monotonic_event_source) {
r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
@@ -463,6 +511,9 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_realtime) {
char buf[FORMAT_TIMESTAMP_MAX];
+
+ add_random(t, &t->next_elapse_realtime);
+
log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
if (t->realtime_event_source) {
diff --git a/src/core/timer.h b/src/core/timer.h
index ac5af6a93c..0599f07818 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -58,6 +58,7 @@ struct Timer {
Unit meta;
usec_t accuracy_usec;
+ usec_t random_usec;
LIST_HEAD(TimerValue, values);
usec_t next_elapse_realtime;
@@ -73,6 +74,7 @@ struct Timer {
bool persistent;
bool wake_system;
+ bool remain_after_elapse;
char *stamp_path;
};
diff --git a/src/core/transaction.c b/src/core/transaction.c
index cf37b5eb75..15e79d00b3 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <fcntl.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "bus-common-errors.h"
diff --git a/src/core/transaction.h b/src/core/transaction.h
index f7aa3df085..5c4a13edab 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -23,10 +23,10 @@
typedef struct Transaction Transaction;
-#include "unit.h"
-#include "manager.h"
-#include "job.h"
#include "hashmap.h"
+#include "job.h"
+#include "manager.h"
+#include "unit.h"
struct Transaction {
/* Jobs to be added */
diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in
new file mode 100644
index 0000000000..9e18a39a67
--- /dev/null
+++ b/src/core/triggers.systemd.in
@@ -0,0 +1,64 @@
+# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
+#
+# This file is part of systemd.
+#
+# Copyright 2015 Zbigniew Jędrzejewski-Szmek
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# The contents of this are an example to be copied into systemd.spec.
+
+%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
+-- This script will run after any package is initially installed or
+-- upgraded. We care about the case where a package is initially
+-- installed, because other cases are covered by the *un scriptlets,
+-- so sometimes we will reload needlessly.
+
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
+elseif pid > 0 then
+ posix.wait(pid)
+end
+
+%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system
+-- On removal, we need to run daemon-reload after any units have been
+-- removed. %transfiletriggerpostun would be ideal, but it does not get
+-- executed for some reason.
+-- On upgrade, we need to run daemon-reload after any new unit files
+-- have been installed, but before %postun scripts in packages get
+-- executed. %transfiletriggerun gets the right list of files
+-- but it is invoked too early (before changes happen).
+-- %filetriggerpostun happens at the right time, but it fires for
+-- every package.
+-- To execute the reload at the right time, we create a state
+-- file in %transfiletriggerun and execute the daemon-reload in
+-- the first %filetriggerpostun.
+
+posix.mkdir("%{_localstatedir}/lib")
+posix.mkdir("%{_localstatedir}/lib/rpm-state")
+posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd")
+io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w")
+
+%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
+if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
+ posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload")
+ posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd")
+ pid = posix.fork()
+ if pid == 0 then
+ assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
+ elseif pid > 0 then
+ posix.wait(pid)
+ end
+end
diff --git a/src/core/unit.c b/src/core/unit.c
index f553f24829..0a02e38aa8 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -132,6 +132,9 @@ static void unit_init(Unit *u) {
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
+
+ if (u->type != UNIT_SLICE)
+ cc->tasks_max = u->manager->default_tasks_max;
}
ec = unit_get_exec_context(u);
@@ -314,9 +317,6 @@ bool unit_check_gc(Unit *u) {
if (state != UNIT_INACTIVE)
return true;
- if (UNIT_VTABLE(u)->no_gc)
- return true;
-
if (u->no_gc)
return true;
@@ -1347,12 +1347,18 @@ static bool unit_assert_test(Unit *u) {
return u->assert_result;
}
+void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, status, unit_status_msg_format, unit_description(u));
+ REENABLE_WARNING;
+}
+
_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
const char *format;
const UnitStatusMessageFormats *format_table;
assert(u);
- assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD);
+ assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD));
if (t != JOB_RELOAD) {
format_table = &UNIT_VTABLE(u)->status_message_formats;
@@ -1377,6 +1383,10 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
assert(u);
+ /* Reload status messages have traditionally not been printed to console. */
+ if (!IN_SET(t, JOB_START, JOB_STOP))
+ return;
+
format = unit_get_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
@@ -1391,7 +1401,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
assert(u);
- if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD)
+ if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
return;
if (log_on_console())
@@ -1423,12 +1433,12 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
}
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
unit_status_log_starting_stopping_reloading(u, t);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (t != JOB_RELOAD)
- unit_status_print_starting_stopping(u, t);
+ unit_status_print_starting_stopping(u, t);
}
/* Errors:
@@ -2896,13 +2906,6 @@ int unit_coldplug(Unit *u) {
return 0;
}
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
- DISABLE_WARNING_FORMAT_NONLITERAL;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL,
- status, unit_status_msg_format, unit_description(u));
- REENABLE_WARNING;
-}
-
bool unit_need_daemon_reload(Unit *u) {
_cleanup_strv_free_ char **t = NULL;
char **path;
@@ -3428,7 +3431,15 @@ int unit_make_transient(Unit *u) {
u->load_state = UNIT_STUB;
u->load_error = 0;
u->transient = true;
+
u->fragment_path = mfree(u->fragment_path);
+ u->source_path = mfree(u->source_path);
+ u->dropin_paths = strv_free(u->dropin_paths);
+ u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
+
+ unit_add_to_dbus_queue(u);
+ unit_add_to_gc_queue(u);
+ unit_add_to_load_queue(u);
return 0;
}
@@ -3704,3 +3715,21 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
return -ELOOP;
}
+
+bool unit_is_pristine(Unit *u) {
+ assert(u);
+
+ /* Check if the unit already exists or is already around,
+ * in a number of different ways. Note that to cater for unit
+ * types such as slice, we are generally fine with units that
+ * are marked UNIT_LOADED even even though nothing was
+ * actually loaded, as those unit types don't require a file
+ * on disk to validly load. */
+
+ return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
+ u->fragment_path ||
+ u->source_path ||
+ !strv_isempty(u->dropin_paths) ||
+ u->job ||
+ u->merged_into);
+}
diff --git a/src/core/unit.h b/src/core/unit.h
index 14e3072146..1681bbf53b 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -30,11 +30,11 @@ typedef struct UnitVTable UnitVTable;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-#include "list.h"
#include "condition.h"
+#include "failure-action.h"
#include "install.h"
+#include "list.h"
#include "unit-name.h"
-#include "failure-action.h"
typedef enum KillOperation {
KILL_TERMINATE,
@@ -242,16 +242,16 @@ typedef enum UnitSetPropertiesMode {
UNIT_PERSISTENT = 2,
} UnitSetPropertiesMode;
-#include "socket.h"
+#include "automount.h"
#include "busname.h"
-#include "target.h"
#include "device.h"
-#include "automount.h"
-#include "swap.h"
-#include "timer.h"
-#include "slice.h"
#include "path.h"
#include "scope.h"
+#include "slice.h"
+#include "socket.h"
+#include "swap.h"
+#include "target.h"
+#include "timer.h"
struct UnitVTable {
/* How much memory does an object of this unit type need */
@@ -403,9 +403,6 @@ struct UnitVTable {
/* Instances make no sense for this type */
bool no_instances:1;
- /* Exclude from automatic gc */
- bool no_gc:1;
-
/* True if transient units of this type are OK */
bool can_transient:1;
};
@@ -589,6 +586,8 @@ int unit_require_mounts_for(Unit *u, const char *path);
bool unit_type_supported(UnitType t);
+bool unit_is_pristine(Unit *u);
+
static inline bool unit_supported(Unit *u) {
return unit_type_supported(u->type);
}
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 642d36912c..469ee7af68 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -542,7 +542,7 @@ static int process_root_password(void) {
lock = take_etc_passwd_lock(arg_root);
if (lock < 0)
- return lock;
+ return log_error_errno(lock, "Failed to take a lock: %m");
if (arg_copy_root_password && arg_root) {
struct spwd *p;
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 5b806a1e69..e0436d794c 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -20,14 +20,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdbool.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
#include <sys/file.h>
-#include <sys/stat.h>
#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "sd-bus.h"
#include "sd-device.h"
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index f7c8d11ace..87b8b77f22 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -248,6 +248,7 @@ static int add_mount(
assert(what);
assert(where);
assert(opts);
+ assert(post);
assert(source);
if (streq_ptr(fstype, "autofs"))
@@ -297,7 +298,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (post && !noauto && !nofail && !automount)
+ if (!noauto && !nofail && !automount)
fprintf(f, "Before=%s\n", post);
if (!automount && opts) {
@@ -337,7 +338,7 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
- if (!noauto && post) {
+ if (!noauto) {
lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
if (!lnk)
return log_oom();
@@ -368,10 +369,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (post)
- fprintf(f,
- "Before=%s\n",
- post);
+ fprintf(f, "Before=%s\n", post);
if (opts) {
r = write_requires_after(f, opts);
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 34852ce381..ce8cecc5cb 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
+#include <blkid/blkid.h>
#include <stdlib.h>
#include <sys/statfs.h>
-#include <blkid/blkid.h>
+#include <unistd.h>
#include "libudev.h"
#include "sd-id128.h"
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index 316a2803d3..2e1259ef68 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
#include <sys/stat.h>
#include "alloc-util.h"
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 92061532b8..dde2baf661 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -21,8 +21,8 @@
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include <sys/utsname.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "bus-util.h"
diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c
index 7b1ac134a0..82f519958c 100644
--- a/src/import/aufs-util.c
+++ b/src/import/aufs-util.c
@@ -21,10 +21,10 @@
#include <ftw.h>
+#include "aufs-util.h"
#include "rm-rf.h"
#include "string-util.h"
#include "util.h"
-#include "aufs-util.h"
static int nftw_cb(
const char *fpath,
diff --git a/src/import/curl-util.c b/src/import/curl-util.c
index 4278466df1..8e531a64fa 100644
--- a/src/import/curl-util.c
+++ b/src/import/curl-util.c
@@ -48,9 +48,7 @@ static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *u
assert(s);
assert(g);
- translated_fd = PTR_TO_INT(hashmap_get(g->translate_fds, INT_TO_PTR(fd+1)));
- assert(translated_fd > 0);
- translated_fd--;
+ translated_fd = PTR_TO_FD(hashmap_get(g->translate_fds, FD_TO_PTR(fd)));
if ((revents & (EPOLLIN|EPOLLOUT)) == (EPOLLIN|EPOLLOUT))
action = CURL_POLL_INOUT;
@@ -79,7 +77,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
assert(curl);
assert(g);
- io = hashmap_get(g->ios, INT_TO_PTR(s+1));
+ io = hashmap_get(g->ios, FD_TO_PTR(s));
if (action == CURL_POLL_REMOVE) {
if (io) {
@@ -91,8 +89,8 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
sd_event_source_set_enabled(io, SD_EVENT_OFF);
sd_event_source_unref(io);
- hashmap_remove(g->ios, INT_TO_PTR(s+1));
- hashmap_remove(g->translate_fds, INT_TO_PTR(fd+1));
+ hashmap_remove(g->ios, FD_TO_PTR(s));
+ hashmap_remove(g->translate_fds, FD_TO_PTR(fd));
safe_close(fd);
}
@@ -143,17 +141,17 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
sd_event_source_set_description(io, "curl-io");
- r = hashmap_put(g->ios, INT_TO_PTR(s+1), io);
+ r = hashmap_put(g->ios, FD_TO_PTR(s), io);
if (r < 0) {
log_oom();
sd_event_source_unref(io);
return -1;
}
- r = hashmap_put(g->translate_fds, INT_TO_PTR(fd+1), INT_TO_PTR(s+1));
+ r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s));
if (r < 0) {
log_oom();
- hashmap_remove(g->ios, INT_TO_PTR(s+1));
+ hashmap_remove(g->ios, FD_TO_PTR(s));
sd_event_source_unref(io);
return -1;
}
@@ -229,7 +227,7 @@ CurlGlue *curl_glue_unref(CurlGlue *g) {
fd = sd_event_source_get_io_fd(io);
assert(fd >= 0);
- hashmap_remove(g->translate_fds, INT_TO_PTR(fd+1));
+ hashmap_remove(g->translate_fds, FD_TO_PTR(fd));
safe_close(fd);
sd_event_source_unref(io);
diff --git a/src/import/curl-util.h b/src/import/curl-util.h
index 6a2aa81c76..eec53c9266 100644
--- a/src/import/curl-util.h
+++ b/src/import/curl-util.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <curl/curl.h>
+#include <sys/types.h>
#include "sd-event.h"
diff --git a/src/import/export-raw.c b/src/import/export-raw.c
index 103d45bf21..28c87594d6 100644
--- a/src/import/export-raw.c
+++ b/src/import/export-raw.c
@@ -20,6 +20,10 @@
***/
#include <sys/sendfile.h>
+
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the POSIX
+ * version which is really broken. We prefer GNU basename(). */
#include <libgen.h>
#undef basename
diff --git a/src/import/export-raw.h b/src/import/export-raw.h
index b71de6cb82..e5e298f6ab 100644
--- a/src/import/export-raw.h
+++ b/src/import/export-raw.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-compress.h"
+#include "macro.h"
typedef struct RawExport RawExport;
diff --git a/src/import/export-tar.h b/src/import/export-tar.h
index ce27a9fc1e..9061e7515d 100644
--- a/src/import/export-tar.h
+++ b/src/import/export-tar.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-compress.h"
+#include "macro.h"
typedef struct TarExport TarExport;
diff --git a/src/import/import-compress.h b/src/import/import-compress.h
index 50d91f732c..0a13232554 100644
--- a/src/import/import-compress.h
+++ b/src/import/import-compress.h
@@ -21,11 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-
+#include <bzlib.h>
#include <lzma.h>
+#include <sys/types.h>
#include <zlib.h>
-#include <bzlib.h>
#include "macro.h"
diff --git a/src/import/import-raw.h b/src/import/import-raw.h
index bf7c770340..626d965cf8 100644
--- a/src/import/import-raw.h
+++ b/src/import/import-raw.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-util.h"
+#include "macro.h"
typedef struct RawImport RawImport;
diff --git a/src/import/import-tar.h b/src/import/import-tar.h
index aaecb51398..d12391572d 100644
--- a/src/import/import-tar.h
+++ b/src/import/import-tar.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-util.h"
+#include "macro.h"
typedef struct TarImport TarImport;
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index d6567ba7ee..a83cffffa0 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -165,7 +165,7 @@ static int hash_url(const char *url, char **ret) {
assert(url);
- siphash24((uint8_t *) &h, url, strlen(url), k.bytes);
+ h = siphash24(url, strlen(url), k.bytes);
if (asprintf(ret, "%"PRIx64, h) < 0)
return -ENOMEM;
diff --git a/src/import/pull-common.h b/src/import/pull-common.h
index 7e6db1862c..ea228bb5c8 100644
--- a/src/import/pull-common.h
+++ b/src/import/pull-common.h
@@ -23,8 +23,8 @@
#include <stdbool.h>
-#include "pull-job.h"
#include "import-util.h"
+#include "pull-job.h"
int pull_make_local_copy(const char *final, const char *root, const char *local, bool force_local);
diff --git a/src/import/pull-dkr.h b/src/import/pull-dkr.h
index 33d18cb394..a95d91205b 100644
--- a/src/import/pull-dkr.h
+++ b/src/import/pull-dkr.h
@@ -22,6 +22,7 @@
#pragma once
#include "sd-event.h"
+
#include "util.h"
typedef enum { DKR_PULL_V1, DKR_PULL_V2 } DkrPullVersion;
diff --git a/src/import/pull-job.h b/src/import/pull-job.h
index 1777bf1c33..56a74a34ef 100644
--- a/src/import/pull-job.h
+++ b/src/import/pull-job.h
@@ -23,9 +23,9 @@
#include <gcrypt.h>
-#include "macro.h"
#include "curl-util.h"
#include "import-compress.h"
+#include "macro.h"
typedef struct PullJob PullJob;
diff --git a/src/import/pull-raw.h b/src/import/pull-raw.h
index b03b4f5c92..0e4e1daf0e 100644
--- a/src/import/pull-raw.h
+++ b/src/import/pull-raw.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-util.h"
+#include "macro.h"
typedef struct RawPull RawPull;
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index e7fcd293f1..2e48167c54 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/prctl.h>
#include <curl/curl.h>
+#include <sys/prctl.h>
#include "sd-daemon.h"
diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h
index 420845ae50..9f02f1ec71 100644
--- a/src/import/pull-tar.h
+++ b/src/import/pull-tar.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "macro.h"
+
#include "import-util.h"
+#include "macro.h"
typedef struct TarPull TarPull;
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index d4f8673187..a35f2b541c 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -19,11 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
+#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
+#include <stdio.h>
#include <sys/epoll.h>
-#include <ctype.h>
+#include <unistd.h>
#include "sd-bus.h"
#include "sd-daemon.h"
diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h
index 14bfadc132..58cb5e70df 100644
--- a/src/journal-remote/journal-remote-parse.h
+++ b/src/journal-remote/journal-remote-parse.h
@@ -22,6 +22,7 @@
#pragma once
#include "sd-event.h"
+
#include "journal-remote-write.h"
typedef enum {
diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h
index 6c2ccb9735..fd81a1c592 100644
--- a/src/journal-remote/journal-remote.h
+++ b/src/journal-remote/journal-remote.h
@@ -23,11 +23,11 @@
#include "sd-event.h"
-#include "hashmap.h"
-#include "microhttpd-util.h"
+#include "hashmap.h"
#include "journal-remote-parse.h"
#include "journal-remote-write.h"
+#include "microhttpd-util.h"
typedef struct MHDDaemonWrapper MHDDaemonWrapper;
diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c
index 3ee6d32bf7..a6d7c3b7e8 100644
--- a/src/journal-remote/journal-upload-journal.c
+++ b/src/journal-remote/journal-upload-journal.c
@@ -19,9 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-
#include <curl/curl.h>
+#include <stdbool.h>
#include "alloc-util.h"
#include "journal-upload.h"
diff --git a/src/journal-remote/journal-upload.h b/src/journal-remote/journal-upload.h
index 3b46fa8cbf..b8cd04d527 100644
--- a/src/journal-remote/journal-upload.h
+++ b/src/journal-remote/journal-upload.h
@@ -2,8 +2,8 @@
#include <inttypes.h>
-#include "sd-journal.h"
#include "sd-event.h"
+#include "sd-journal.h"
typedef enum {
ENTRY_CURSOR = 0, /* Nothing actually written yet. */
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index b2c398a845..09e6da0031 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -32,10 +32,10 @@
#include "alloc-util.h"
#include "log.h"
#include "macro.h"
+#include "microhttpd-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-#include "microhttpd-util.h"
void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
char *f;
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index b2feb9180a..3e8c4fa6d1 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -21,8 +21,8 @@
#pragma once
-#include <stdarg.h>
#include <microhttpd.h>
+#include <stdarg.h>
#include "macro.h"
diff --git a/src/journal/audit-type.c b/src/journal/audit-type.c
index 4888c7d05d..086bf7e7e3 100644
--- a/src/journal/audit-type.c
+++ b/src/journal/audit-type.c
@@ -25,8 +25,7 @@
# include <libaudit.h>
#endif
-#include "audit-type.h"
-#include "macro.h"
#include "missing.h"
-
+#include "audit-type.h"
#include "audit_type-to-name.h"
+#include "macro.h"
diff --git a/src/journal/catalog.h b/src/journal/catalog.h
index a72ecf6de7..bcc73c2631 100644
--- a/src/journal/catalog.h
+++ b/src/journal/catalog.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include "sd-id128.h"
+
#include "hashmap.h"
#include "strbuf.h"
diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c
index 39bc2e4270..09ab60c6c4 100644
--- a/src/journal/coredump-vacuum.c
+++ b/src/journal/coredump-vacuum.c
@@ -157,8 +157,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Can't open coredump directory: %m");
- return -errno;
+ return log_error_errno(errno, "Can't open coredump directory: %m");
}
for (;;) {
@@ -183,7 +182,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
if (errno == ENOENT)
continue;
- log_warning("Failed to stat /var/lib/systemd/coredump/%s", de->d_name);
+ log_warning_errno(errno, "Failed to stat /var/lib/systemd/coredump/%s: %m", de->d_name);
continue;
}
@@ -201,7 +200,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
t = timespec_load(&st.st_mtim);
- c = hashmap_get(h, UINT32_TO_PTR(uid));
+ c = hashmap_get(h, UID_TO_PTR(uid));
if (c) {
if (t < c->oldest_mtime) {
@@ -229,7 +228,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
n->oldest_mtime = t;
- r = hashmap_put(h, UINT32_TO_PTR(uid), n);
+ r = hashmap_put(h, UID_TO_PTR(uid), n);
if (r < 0)
return log_oom();
@@ -259,8 +258,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
if (errno == ENOENT)
continue;
- log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file);
- return -errno;
+ return log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file);
} else
log_info("Removed old coredump %s.", worst->oldest_file);
}
@@ -268,6 +266,5 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
return 0;
fail:
- log_error_errno(errno, "Failed to read directory: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to read directory: %m");
}
diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h
index 5959b1fed2..b79221fc2e 100644
--- a/src/journal/fsprg.h
+++ b/src/journal/fsprg.h
@@ -25,8 +25,8 @@
*
*/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
#include "macro.h"
#include "util.h"
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 0c4ac5cdc3..aeec83da1e 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -24,10 +24,10 @@
#include "fd-util.h"
#include "fsprg.h"
+#include "hexdecoct.h"
#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
-#include "hexdecoct.h"
static uint64_t journal_file_tag_seqnum(JournalFile *f) {
uint64_t r;
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 898d12d992..46c1f3278e 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -29,11 +29,11 @@
#include "sd-id128.h"
-#include "sparse-endian.h"
+#include "hashmap.h"
#include "journal-def.h"
#include "macro.h"
#include "mmap-cache.h"
-#include "hashmap.h"
+#include "sparse-endian.h"
typedef struct JournalMetrics {
/* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index 06847402e0..c3e75ad240 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <sys/types.h>
#include "sd-id128.h"
#include "sd-journal.h"
diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c
index 1db66e89c6..257ddb302b 100644
--- a/src/journal/journal-qrcode.c
+++ b/src/journal/journal-qrcode.c
@@ -20,12 +20,11 @@
***/
#include <assert.h>
-#include <stdio.h>
#include <errno.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
#include <qrencode.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "journal-qrcode.h"
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 3676cb8788..715847e018 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <sys/mman.h>
#include <fcntl.h>
#include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "compress.h"
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 75a48c761c..d9a8063d31 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2247,7 +2247,8 @@ int main(int argc, char *argv[]) {
if (arg_follow)
need_seek = true;
else {
- printf("-- No entries --\n");
+ if (!arg_quiet)
+ printf("-- No entries --\n");
goto finish;
}
}
diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h
index 68cdfb3410..5c88bb6383 100644
--- a/src/journal/journald-audit.h
+++ b/src/journal/journald-audit.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "socket-util.h"
#include "journald-server.h"
+#include "socket-util.h"
void server_process_audit_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const union sockaddr_union *sa, socklen_t salen);
diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c
index 89f3d4b42f..04487c29b5 100644
--- a/src/journal/journald-console.c
+++ b/src/journal/journald-console.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <time.h>
#include <fcntl.h>
#include <sys/socket.h>
+#include <time.h>
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index 434ddc8ac9..1c406aef8e 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -24,11 +24,11 @@
#include "alloc-util.h"
#include "hashmap.h"
+#include "journald-rate-limit.h"
#include "list.h"
#include "random-util.h"
#include "string-util.h"
#include "util.h"
-#include "journald-rate-limit.h"
#define POOLS_MAX 5
#define BUCKETS_MAX 127
@@ -162,7 +162,7 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r,
siphash24_init(&state, r->hash_key);
string_hash_func(g->id, &state);
- siphash24_finalize((uint8_t*)&g->hash, &state);
+ g->hash = siphash24_finalize(&state);
journal_rate_limit_vacuum(r, ts);
@@ -230,7 +230,7 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
siphash24_init(&state, r->hash_key);
string_hash_func(id, &state);
- siphash24_finalize((uint8_t*)&h, &state);
+ h = siphash24_finalize(&state);
g = r->buckets[h % BUCKETS_MAX];
LIST_FOREACH(bucket, g, g)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index be913d26ef..7d11a568aa 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -69,6 +69,7 @@
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "user-util.h"
#define USER_JOURNALS_MAX 1024
@@ -281,7 +282,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
if (r < 0)
return s->system_journal;
- f = ordered_hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
+ f = ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid));
if (f)
return f;
@@ -302,7 +303,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
server_fix_perms(s, f, uid);
- r = ordered_hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
+ r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);
if (r < 0) {
journal_file_close(f);
return s->system_journal;
@@ -348,7 +349,7 @@ void server_rotate(Server *s) {
(void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
- r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
+ r = do_rotate(s, &f, "user", s->seal, PTR_TO_UID(k));
if (r >= 0)
ordered_hashmap_replace(s->user_journals, k, f);
else if (!f)
@@ -359,7 +360,6 @@ void server_rotate(Server *s) {
void server_sync(Server *s) {
JournalFile *f;
- void *k;
Iterator i;
int r;
@@ -369,7 +369,7 @@ void server_sync(Server *s) {
log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
}
- ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
+ ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) {
r = journal_file_set_offline(f);
if (r < 0)
log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c
index 69540f1141..88bea3b86e 100644
--- a/src/journal/journald-wall.c
+++ b/src/journal/journald-wall.c
@@ -22,10 +22,10 @@
#include "alloc-util.h"
#include "formats-util.h"
#include "journald-server.h"
+#include "journald-wall.h"
#include "process-util.h"
#include "string-util.h"
#include "utmp-wtmp.h"
-#include "journald-wall.h"
void server_forward_wall(
Server *s,
diff --git a/src/journal/journald.c b/src/journal/journald.c
index b137e3c7be..b9f5c099e1 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -21,16 +21,15 @@
#include <unistd.h>
-#include "sd-messages.h"
#include "sd-daemon.h"
+#include "sd-messages.h"
+#include "formats-util.h"
#include "journal-authenticate.h"
-#include "journald-server.h"
#include "journald-kmsg.h"
+#include "journald-server.h"
#include "journald-syslog.h"
-
#include "sigbus.h"
-#include "formats-util.h"
int main(int argc, char *argv[]) {
Server server;
diff --git a/src/journal/lookup3.c b/src/journal/lookup3.c
index 52ffdf7b1d..3d791234f4 100644
--- a/src/journal/lookup3.c
+++ b/src/journal/lookup3.c
@@ -40,10 +40,10 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
*/
/* #define SELF_TEST 1 */
-#include <stdio.h> /* defines printf for tests */
-#include <time.h> /* defines time_t for timings in the test */
#include <stdint.h> /* defines uint32_t etc */
+#include <stdio.h> /* defines printf for tests */
#include <sys/param.h> /* attempt to define endianness */
+#include <time.h> /* defines time_t for timings in the test */
#ifdef linux
# include <endian.h> /* attempt to define endianness */
#endif
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index 3cb1dfa986..5a07ddda76 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -24,13 +24,14 @@
#include <sys/mman.h>
#include "alloc-util.h"
+#include "fd-util.h"
#include "hashmap.h"
#include "list.h"
#include "log.h"
-#include "util.h"
#include "macro.h"
-#include "sigbus.h"
#include "mmap-cache.h"
+#include "sigbus.h"
+#include "util.h"
typedef struct Window Window;
typedef struct Context Context;
@@ -289,7 +290,7 @@ static void fd_free(FileDescriptor *f) {
window_free(f->windows);
if (f->cache)
- assert_se(hashmap_remove(f->cache->fds, INT_TO_PTR(f->fd + 1)));
+ assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd)));
free(f);
}
@@ -301,7 +302,7 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) {
assert(m);
assert(fd >= 0);
- f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
+ f = hashmap_get(m->fds, FD_TO_PTR(fd));
if (f)
return f;
@@ -316,7 +317,7 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) {
f->cache = m;
f->fd = fd;
- r = hashmap_put(m->fds, UINT_TO_PTR(fd + 1), f);
+ r = hashmap_put(m->fds, FD_TO_PTR(fd), f);
if (r < 0) {
free(f);
return NULL;
@@ -429,7 +430,7 @@ static int find_mmap(
assert(fd >= 0);
assert(size > 0);
- f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
+ f = hashmap_get(m->fds, FD_TO_PTR(fd));
if (!f)
return 0;
@@ -679,7 +680,7 @@ bool mmap_cache_got_sigbus(MMapCache *m, int fd) {
mmap_cache_process_sigbus(m);
- f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
+ f = hashmap_get(m->fds, FD_TO_PTR(fd));
if (!f)
return false;
@@ -698,7 +699,7 @@ void mmap_cache_close_fd(MMapCache *m, int fd) {
mmap_cache_process_sigbus(m);
- f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
+ f = hashmap_get(m->fds, FD_TO_PTR(fd));
if (!f)
return;
diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c
index aea8fd15e6..25980b7744 100644
--- a/src/journal/test-catalog.c
+++ b/src/journal/test-catalog.c
@@ -20,10 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <locale.h>
-#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <locale.h>
+#include <unistd.h>
#include "sd-messages.h"
diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c
index 040c7d58fb..8f56ea1907 100644
--- a/src/journal/test-journal-enum.c
+++ b/src/journal/test-journal-enum.c
@@ -23,9 +23,9 @@
#include "sd-journal.h"
+#include "journal-internal.h"
#include "log.h"
#include "macro.h"
-#include "journal-internal.h"
int main(int argc, char *argv[]) {
unsigned n = 0;
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 4ad89fe4b6..5c055ef748 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -20,8 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <fcntl.h>
+#include <unistd.h>
#include "sd-journal.h"
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index 887a83efe1..a7abb11fba 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
-#include <fcntl.h>
#include "fd-util.h"
#include "journal-file.h"
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 01d4bc968a..266e0d5473 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -22,11 +22,11 @@
#include <fcntl.h>
#include <unistd.h>
-#include "log.h"
-#include "rm-rf.h"
-#include "journal-file.h"
#include "journal-authenticate.h"
+#include "journal-file.h"
#include "journal-vacuum.h"
+#include "log.h"
+#include "rm-rf.h"
static bool arg_keep = false;
diff --git a/src/libsystemd-network/arp-util.h b/src/libsystemd-network/arp-util.h
index 44e5c893a7..63c559f8dd 100644
--- a/src/libsystemd-network/arp-util.h
+++ b/src/libsystemd-network/arp-util.h
@@ -23,8 +23,8 @@
#include <netinet/if_ether.h>
-#include "sparse-endian.h"
#include "socket-util.h"
+#include "sparse-endian.h"
int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index 51ee7bcce4..d7ae865557 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -35,6 +35,7 @@
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
sd_id128_t machine_id;
+ uint64_t hash;
int r;
assert(duid);
@@ -50,8 +51,9 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
*len = sizeof(duid->type) + sizeof(duid->en);
/* a bit of snake-oil perhaps, but no need to expose the machine-id
- directly */
- siphash24(duid->en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
+ directly; duid->en.id might not be aligned, so we need to copy */
+ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
+ memcpy(duid->en.id, &hash, sizeof(duid->en.id));
return 0;
}
@@ -84,10 +86,12 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
}
if (name)
- siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
+ id = siphash24(name, strlen(name), HASH_KEY.bytes);
else
/* fall back to MAC address if no predictable name available */
- siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes);
+ id = siphash24(mac, mac_len, HASH_KEY.bytes);
+
+ id = htole64(id);
/* fold into 32 bits */
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index a5daaa543a..7038212bcf 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -47,8 +47,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
const void *option, void *userdata);
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *userdata);
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, size_t optlen,
diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index c6b97ca8f7..138bdd9691 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -25,12 +25,11 @@
#include <stdint.h>
#include <linux/if_packet.h>
-#include "util.h"
-#include "list.h"
+#include "sd-dhcp-client.h"
#include "dhcp-protocol.h"
-
-#include "sd-dhcp-client.h"
+#include "list.h"
+#include "util.h"
struct sd_dhcp_route {
struct in_addr dst_addr;
diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index 36be7d54ed..1de7f3639c 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -19,10 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdint.h>
-#include <string.h>
#include <errno.h>
+#include <stdint.h>
#include <stdio.h>
+#include <string.h>
+
+#include "alloc-util.h"
+#include "utf8.h"
#include "dhcp-internal.h"
@@ -139,72 +142,84 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
- uint8_t *message_type, dhcp_option_cb_t cb,
+ uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
void *userdata) {
uint8_t code, len;
+ const uint8_t *option;
size_t offset = 0;
while (offset < buflen) {
- switch (options[offset]) {
- case DHCP_OPTION_PAD:
- offset++;
+ code = options[offset ++];
- break;
+ switch (code) {
+ case DHCP_OPTION_PAD:
+ continue;
case DHCP_OPTION_END:
return 0;
+ }
- case DHCP_OPTION_MESSAGE_TYPE:
- if (buflen < offset + 3)
- return -ENOBUFS;
+ if (buflen < offset + 1)
+ return -ENOBUFS;
+
+ len = options[offset ++];
+
+ if (buflen < offset + len)
+ return -EINVAL;
+
+ option = &options[offset];
- len = options[++offset];
+ switch (code) {
+ case DHCP_OPTION_MESSAGE_TYPE:
if (len != 1)
return -EINVAL;
if (message_type)
- *message_type = options[++offset];
- else
- offset++;
-
- offset++;
+ *message_type = *option;
break;
- case DHCP_OPTION_OVERLOAD:
- if (buflen < offset + 3)
- return -ENOBUFS;
-
- len = options[++offset];
- if (len != 1)
+ case DHCP_OPTION_ERROR_MESSAGE:
+ if (len == 0)
return -EINVAL;
- if (overload)
- *overload = options[++offset];
- else
- offset++;
+ if (error_message) {
+ _cleanup_free_ char *string = NULL;
- offset++;
+ /* Accept a trailing NUL byte */
+ if (memchr(option, 0, len - 1))
+ return -EINVAL;
- break;
+ string = strndup((const char *) option, len);
+ if (!string)
+ return -ENOMEM;
- default:
- if (buflen < offset + 3)
- return -ENOBUFS;
+ if (!ascii_is_valid(string))
+ return -EINVAL;
- code = options[offset];
- len = options[++offset];
+ free(*error_message);
+ *error_message = string;
+ string = NULL;
+ }
- if (buflen < ++offset + len)
+ break;
+ case DHCP_OPTION_OVERLOAD:
+ if (len != 1)
return -EINVAL;
- if (cb)
- cb(code, len, &options[offset], userdata);
+ if (overload)
+ *overload = *option;
+
+ break;
- offset += len;
+ default:
+ if (cb)
+ cb(code, len, option, userdata);
break;
}
+
+ offset += len;
}
if (offset < buflen)
@@ -213,8 +228,8 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *userdata) {
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
+ _cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;
int r;
@@ -227,27 +242,29 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
len -= sizeof(DHCPMessage);
- r = parse_options(message->options, len, &overload, &message_type,
- cb, userdata);
+ r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
if (overload & DHCP_OVERLOAD_FILE) {
- r = parse_options(message->file, sizeof(message->file),
- NULL, &message_type, cb, userdata);
+ r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
if (overload & DHCP_OVERLOAD_SNAME) {
- r = parse_options(message->sname, sizeof(message->sname),
- NULL, &message_type, cb, userdata);
+ r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
- if (message_type)
- return message_type;
+ if (message_type == 0)
+ return -ENOMSG;
+
+ if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) {
+ *_error_message = error_message;
+ error_message = NULL;
+ }
- return -ENOMSG;
+ return message_type;
}
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index cd7f5095ca..9ff42b155e 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -19,13 +19,12 @@
***/
#include <errno.h>
-#include <string.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
+#include <string.h>
-
-#include "dhcp-protocol.h"
#include "dhcp-internal.h"
+#include "dhcp-protocol.h"
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h
index 88a81d2866..f65529a00e 100644
--- a/src/libsystemd-network/dhcp-protocol.h
+++ b/src/libsystemd-network/dhcp-protocol.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/udp.h>
#include <netinet/ip.h>
+#include <netinet/udp.h>
#include <stdint.h>
#include "macro.h"
@@ -132,11 +132,13 @@ enum {
DHCP_OPTION_MESSAGE_TYPE = 53,
DHCP_OPTION_SERVER_IDENTIFIER = 54,
DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
+ DHCP_OPTION_ERROR_MESSAGE = 56,
DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
DHCP_OPTION_RENEWAL_T1_TIME = 58,
DHCP_OPTION_REBINDING_T2_TIME = 59,
DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
DHCP_OPTION_CLIENT_IDENTIFIER = 61,
+ DHCP_OPTION_FQDN = 81,
DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
@@ -144,3 +146,12 @@ enum {
DHCP_OPTION_PRIVATE_LAST = 254,
DHCP_OPTION_END = 255,
};
+
+#define DHCP_MAX_FQDN_LENGTH 255
+
+enum {
+ DHCP_FQDN_FLAG_S = (1 << 0),
+ DHCP_FQDN_FLAG_O = (1 << 1),
+ DHCP_FQDN_FLAG_E = (1 << 2),
+ DHCP_FQDN_FLAG_N = (1 << 3),
+};
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index 3b88b93d9a..a42f622c37 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -22,14 +22,13 @@
#pragma once
-#include "sd-event.h"
#include "sd-dhcp-server.h"
+#include "sd-event.h"
+#include "dhcp-internal.h"
#include "hashmap.h"
-#include "util.h"
#include "log.h"
-
-#include "dhcp-internal.h"
+#include "util.h"
typedef struct DHCPClientId {
size_t length;
diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h
index 4edecf7711..f6cf0b30d3 100644
--- a/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/libsystemd-network/dhcp6-lease-internal.h
@@ -25,6 +25,7 @@
#include <stdint.h>
#include "sd-dhcp6-lease.h"
+
#include "dhcp6-internal.h"
struct sd_dhcp6_lease {
diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c
index 318ee9c4b4..fd2d60c9d5 100644
--- a/src/libsystemd-network/dhcp6-network.c
+++ b/src/libsystemd-network/dhcp6-network.c
@@ -33,36 +33,32 @@
#include "socket-util.h"
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
- struct in6_pktinfo pktinfo = {
- .ipi6_ifindex = index,
- };
union sockaddr_union src = {
.in6.sin6_family = AF_INET6,
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
- .in6.sin6_addr = IN6ADDR_ANY_INIT,
+ .in6.sin6_scope_id = index,
};
_cleanup_close_ int s = -1;
int r, off = 0, on = 1;
- if (local_address)
- memcpy(&src.in6.sin6_addr, local_address,
- sizeof(src.in6.sin6_addr));
+ assert(index > 0);
+ assert(local_address);
+
+ src.in6.sin6_addr = *local_address;
- s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- IPPROTO_UDP);
+ s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
if (s < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo,
- sizeof(pktinfo));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
+ r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (r < 0)
return -errno;
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index 0f46df6a1b..850212aea1 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/in.h>
#include <errno.h>
+#include <netinet/in.h>
#include <string.h>
#include "alloc-util.h"
@@ -360,7 +360,6 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
/* End of name */
break;
else if (c <= 63) {
- _cleanup_free_ char *t = NULL;
const char *label;
/* Literal label */
@@ -369,21 +368,20 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
if (pos > optlen)
return -EMSGSIZE;
- r = dns_label_escape(label, c, &t);
- if (r < 0)
- goto fail;
-
- if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) {
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
r = -ENOMEM;
goto fail;
}
- if (!first)
- ret[n++] = '.';
- else
+ if (first)
first = false;
+ else
+ ret[n++] = '.';
+
+ r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ goto fail;
- memcpy(ret + n, t, r);
n += r;
continue;
} else {
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index 91308bf6c3..acad9d7d6a 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -47,17 +47,15 @@ int icmp6_bind_router_solicitation(int index) {
.ipv6mr_interface = index,
};
_cleanup_close_ int s = -1;
- int r, zero = 0, hops = 255;
+ int r, zero = 0, one = 1, hops = 255;
- s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
- IPPROTO_ICMPV6);
+ s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (s < 0)
return -errno;
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
- r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
- sizeof(filter));
+ r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter));
if (r < 0)
return -errno;
@@ -65,23 +63,23 @@ int icmp6_bind_router_solicitation(int index) {
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
Empirical experiments indicates otherwise and therefore an
IPV6_MULTICAST_IF socket option is used here instead */
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
- sizeof(index));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
- sizeof(zero));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
- sizeof(hops));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (r < 0)
+ return -errno;
+
+ r = setsockopt(s, SOL_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
if (r < 0)
return -errno;
@@ -101,25 +99,25 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
struct ether_addr rs_opt_mac;
} _packed_ rs = {
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
+ .rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR,
+ .rs_opt.nd_opt_len = 1,
};
- struct iovec iov[1] = {
- { &rs, },
+ struct iovec iov = {
+ .iov_base = &rs,
+ .iov_len = sizeof(rs),
};
struct msghdr msg = {
.msg_name = &dst,
.msg_namelen = sizeof(dst),
- .msg_iov = iov,
+ .msg_iov = &iov,
.msg_iovlen = 1,
};
int r;
- if (ether_addr) {
- memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
- rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
- rs.rs_opt.nd_opt_len = 1;
- iov[0].iov_len = sizeof(rs);
- } else
- iov[0].iov_len = sizeof(rs.rs);
+ assert(s >= 0);
+ assert(ether_addr);
+
+ rs.rs_opt_mac = *ether_addr;
r = sendmsg(s, &msg, 0);
if (r < 0)
diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c
index 97b6b485d2..1f1a49adbf 100644
--- a/src/libsystemd-network/lldp-port.c
+++ b/src/libsystemd-network/lldp-port.c
@@ -22,9 +22,9 @@
#include "alloc-util.h"
#include "async.h"
-#include "lldp-port.h"
-#include "lldp-network.h"
#include "lldp-internal.h"
+#include "lldp-network.h"
+#include "lldp-port.h"
int lldp_port_start(lldp_port *p) {
int r;
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
index 7890160497..66343147a1 100644
--- a/src/libsystemd-network/lldp-tlv.c
+++ b/src/libsystemd-network/lldp-tlv.c
@@ -20,8 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/ethernet.h>
#include <arpa/inet.h>
+#include <net/ethernet.h>
#include "alloc-util.h"
#include "lldp-tlv.h"
diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h
index ca1da113d5..f5cd77477f 100644
--- a/src/libsystemd-network/lldp-tlv.h
+++ b/src/libsystemd-network/lldp-tlv.h
@@ -24,12 +24,12 @@
#include <net/ethernet.h>
-#include "util.h"
-#include "lldp.h"
-#include "list.h"
-
#include "sd-lldp.h"
+#include "list.h"
+#include "lldp.h"
+#include "util.h"
+
typedef struct sd_lldp_packet tlv_packet;
typedef struct sd_lldp_section tlv_section;
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 52d76e443e..a4d4f1ae2f 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -29,9 +29,9 @@
#include "condition.h"
#include "conf-parser.h"
#include "dhcp-lease-internal.h"
+#include "hexdecoct.h"
#include "log.h"
#include "network-internal.h"
-#include "hexdecoct.h"
#include "parse-util.h"
#include "siphash24.h"
#include "string-util.h"
@@ -56,7 +56,7 @@ const char *net_get_name(struct udev_device *device) {
#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
-int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
+int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
size_t l, sz = 0;
const char *name = NULL;
int r;
@@ -81,7 +81,7 @@ int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8
/* Let's hash the machine ID plus the device name. We
* use a fixed, but originally randomly created hash
* key here. */
- siphash24(result, v, sz, HASH_KEY.bytes);
+ *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
return 0;
}
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index d5d4ef42f2..8a30921966 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -23,8 +23,8 @@
#include <stdbool.h>
-#include "udev.h"
#include "condition.h"
+#include "udev.h"
bool net_match_config(const struct ether_addr *match_mac,
char * const *match_path,
@@ -62,7 +62,7 @@ int config_parse_ifalias(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 net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]);
+int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
const char *net_get_name(struct udev_device *device);
void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size);
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 137537253a..7deb00af9c 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -34,6 +34,8 @@
#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
+#include "dns-domain.h"
+#include "hostname-util.h"
#include "random-util.h"
#include "string-util.h"
#include "util.h"
@@ -298,6 +300,9 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
assert_return(client, -EINVAL);
+ if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
+ return -EINVAL;
+
if (streq_ptr(client->hostname, hostname))
return 0;
@@ -539,6 +544,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
return 0;
}
+static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset,
+ const char *fqdn) {
+ uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
+ int r;
+
+ buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
+ DHCP_FQDN_FLAG_E; /* Canonical wire format */
+ buffer[1] = 0; /* RCODE1 (deprecated) */
+ buffer[2] = 0; /* RCODE2 (deprecated) */
+
+ r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3);
+ if (r > 0)
+ r = dhcp_option_append(message, optlen, optoffset, 0,
+ DHCP_OPTION_FQDN, 3 + r, buffer);
+
+ return r;
+}
+
static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
size_t len) {
dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
@@ -576,13 +599,21 @@ static int client_send_discover(sd_dhcp_client *client) {
return r;
}
- /* it is unclear from RFC 2131 if client should send hostname in
- DHCPDISCOVER but dhclient does and so we do as well
- */
if (client->hostname) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
- DHCP_OPTION_HOST_NAME,
- strlen(client->hostname), client->hostname);
+ /* According to RFC 4702 "clients that send the Client FQDN option in
+ their messages MUST NOT also send the Host Name option". Just send
+ one of the two depending on the hostname type.
+ */
+ if (dns_name_is_single_label(client->hostname)) {
+ /* it is unclear from RFC 2131 if client should send hostname in
+ DHCPDISCOVER but dhclient does and so we do as well
+ */
+ r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ DHCP_OPTION_HOST_NAME,
+ strlen(client->hostname), client->hostname);
+ } else
+ r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
+ client->hostname);
if (r < 0)
return r;
}
@@ -688,9 +719,13 @@ static int client_send_request(sd_dhcp_client *client) {
}
if (client->hostname) {
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- DHCP_OPTION_HOST_NAME,
- strlen(client->hostname), client->hostname);
+ if (dns_name_is_single_label(client->hostname))
+ r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
+ DHCP_OPTION_HOST_NAME,
+ strlen(client->hostname), client->hostname);
+ else
+ r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
+ client->hostname);
if (r < 0)
return r;
}
@@ -1047,7 +1082,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return r;
}
- r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
+ r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
if (r != DHCP_OFFER) {
log_dhcp_client(client, "received message was not an OFFER, ignoring");
return -ENOMSG;
@@ -1086,7 +1121,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
size_t len) {
int r;
- r = dhcp_option_parse(force, len, NULL, NULL);
+ r = dhcp_option_parse(force, len, NULL, NULL, NULL);
if (r != DHCP_FORCERENEW)
return -ENOMSG;
@@ -1098,6 +1133,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
size_t len) {
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
+ _cleanup_free_ char *error_message = NULL;
int r;
r = dhcp_lease_new(&lease);
@@ -1112,9 +1148,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
return r;
}
- r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
+ r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
if (r == DHCP_NAK) {
- log_dhcp_client(client, "NAK");
+ log_dhcp_client(client, "NAK: %s", strna(error_message));
return -EADDRNOTAVAIL;
}
@@ -1478,9 +1514,8 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0)
- return r;
-
- if (buflen < 0)
+ return -errno;
+ else if (buflen < 0)
/* this can't be right */
return -EIO;
@@ -1490,26 +1525,28 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
len = read(fd, message, buflen);
if (len < 0) {
- log_dhcp_client(client, "could not receive message from UDP "
- "socket: %m");
- return 0;
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp_client(client, "Could not receive message from UDP socket: %m");
+ return -errno;
} else if ((size_t)len < sizeof(DHCPMessage)) {
- log_dhcp_client(client, "too small to be a DHCP message: ignoring");
+ log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
return 0;
}
if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
- log_dhcp_client(client, "not a DHCP message: ignoring");
+ log_dhcp_client(client, "Not a DHCP message: ignoring");
return 0;
}
if (message->op != BOOTREPLY) {
- log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
+ log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
return 0;
}
if (message->htype != client->arp_type) {
- log_dhcp_client(client, "packet type does not match client type");
+ log_dhcp_client(client, "Packet type does not match client type");
return 0;
}
@@ -1523,13 +1560,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
}
if (message->hlen != expected_hlen) {
- log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
+ log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
return 0;
}
if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
- log_dhcp_client(client, "received chaddr does not match "
- "expected: ignoring");
+ log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
return 0;
}
@@ -1537,8 +1573,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
be32toh(message->xid) != client->xid) {
/* in BOUND state, we may receive FORCERENEW with xid set by server,
so ignore the xid in this case */
- log_dhcp_client(client, "received xid (%u) does not match "
- "expected (%u): ignoring",
+ log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
be32toh(message->xid), client->xid);
return 0;
}
@@ -1567,9 +1602,8 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0)
- return r;
-
- if (buflen < 0)
+ return -errno;
+ else if (buflen < 0)
/* this can't be right */
return -EIO;
@@ -1582,9 +1616,12 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- log_dhcp_client(client, "could not receive message from raw "
- "socket: %m");
- return 0;
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp_client(client, "Could not receive message from raw socket: %m");
+
+ return -errno;
} else if ((size_t)len < sizeof(DHCPPacket))
return 0;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 8befedc500..fccdc01bc3 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -661,7 +661,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
break;
default:
- log_debug("Ignoring option DHCP option %i while parsing.", code);
+ log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
break;
}
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 8d0d9955c3..587ff936ba 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -699,6 +699,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length) {
_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
+ _cleanup_free_ char *error_message = NULL;
DHCPLease *existing_lease;
int type, r;
@@ -714,7 +715,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (!req)
return -ENOMEM;
- type = dhcp_option_parse(message, length, parse_request, req);
+ type = dhcp_option_parse(message, length, parse_request, req, &error_message);
if (type < 0)
return 0;
@@ -753,7 +754,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
siphash24_init(&state, HASH_KEY.bytes);
client_id_hash_func(&req->client_id, &state);
- siphash24_finalize((uint8_t*)&hash, &state);
+ hash = htole64(siphash24_finalize(&state));
next_offer = hash % server->pool_size;
for (i = 0; i < server->pool_size; i++) {
@@ -784,8 +785,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
break;
}
case DHCP_DECLINE:
- log_dhcp_server(server, "DECLINE (0x%x)",
- be32toh(req->message->xid));
+ log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
/* TODO: make sure we don't offer this address again */
@@ -963,10 +963,10 @@ static int server_receive_message(sd_event_source *s, int fd,
if (ioctl(fd, FIONREAD, &buflen) < 0)
return -errno;
- if (buflen < 0)
+ else if (buflen < 0)
return -EIO;
- message = malloc0(buflen);
+ message = malloc(buflen);
if (!message)
return -ENOMEM;
@@ -974,9 +974,12 @@ static int server_receive_message(sd_event_source *s, int fd,
iov.iov_len = buflen;
len = recvmsg(fd, &msg, 0);
- if (len < buflen)
- return 0;
- else if ((size_t)len < sizeof(DHCPMessage))
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return -errno;
+ } else if ((size_t)len < sizeof(DHCPMessage))
return 0;
CMSG_FOREACH(cmsg, &msg) {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index e00ca2b00d..36d909a4c5 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -32,6 +32,7 @@
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
#include "fd-util.h"
+#include "in-addr-util.h"
#include "network-internal.h"
#include "random-util.h"
#include "string-table.h"
@@ -46,6 +47,7 @@ struct sd_dhcp6_client {
sd_event *event;
int event_priority;
int index;
+ struct in6_addr local_address;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
@@ -133,6 +135,18 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
return 0;
}
+int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
+ assert_return(client, -EINVAL);
+ assert_return(local_address, -EINVAL);
+ assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
+
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+ client->local_address = *local_address;
+
+ return 0;
+}
+
int sd_dhcp6_client_set_mac(
sd_dhcp6_client *client,
const uint8_t *addr, size_t addr_len,
@@ -259,12 +273,12 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
assert_return(client, -EINVAL);
- assert_return(ret, -EINVAL);
if (!client->lease)
return -ENOMSG;
- *ret = client->lease;
+ if (ret)
+ *ret = client->lease;
return 0;
}
@@ -881,7 +895,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
- _cleanup_free_ DHCP6Message *message;
+ _cleanup_free_ DHCP6Message *message = NULL;
int r, buflen, len;
assert(s);
@@ -889,18 +903,26 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
assert(client->event);
r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0 || buflen <= 0)
- buflen = DHCP6_MIN_OPTIONS_SIZE;
+ if (r < 0)
+ return -errno;
+ else if (buflen < 0)
+ /* This really should not happen */
+ return -EIO;
- message = malloc0(buflen);
+ message = malloc(buflen);
if (!message)
return -ENOMEM;
len = read(fd, message, buflen);
- if ((size_t)len < sizeof(DHCP6Message)) {
- log_dhcp6_client(client, "could not receive message from UDP socket: %m");
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
+
+ return -errno;
+ } else if ((size_t)len < sizeof(DHCP6Message))
return 0;
- }
switch(message->type) {
case DHCP6_SOLICIT:
@@ -1135,9 +1157,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
+ assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
- return -EALREADY;
+ return -EBUSY;
r = client_reset(client);
if (r < 0)
@@ -1151,7 +1174,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
if (r < 0)
return r;
- r = dhcp6_network_bind_udp_socket(client->index, NULL);
+ r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 0d915e20e7..30a7ef5785 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -101,6 +101,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
if (!ll)
return -ENOMEM;
+ ll->n_ref = 1;
+
r = sd_ipv4acd_new(&ll->acd);
if (r < 0)
return r;
@@ -109,8 +111,6 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
if (r < 0)
return r;
- ll->n_ref = 1;
-
*ret = ll;
ll = NULL;
@@ -143,15 +143,14 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
assert_return(ll, -EINVAL);
if (!ll->random_data) {
- uint8_t seed[8];
+ uint64_t seed;
/* If no random data is set, generate some from the MAC */
- siphash24(seed, &addr->ether_addr_octet,
- ETH_ALEN, HASH_KEY.bytes);
+ seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes);
assert_cc(sizeof(unsigned) <= 8);
- r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed);
+ r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed));
if (r < 0)
return r;
}
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index 0881973e7f..f2bce3b99f 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -32,6 +32,7 @@
#include "in-addr-util.h"
#include "list.h"
#include "socket-util.h"
+#include "string-util.h"
#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
#define NDISC_MAX_ROUTER_SOLICITATIONS 3
@@ -417,8 +418,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
return 0;
}
-static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
- ssize_t len) {
+static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) {
void *opt;
struct nd_opt_hdr *opt_hdr;
@@ -481,30 +481,86 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_free_ struct nd_router_advert *ra = NULL;
sd_ndisc *nd = userdata;
- int r, buflen = 0, pref, stateful;
- union sockaddr_union router = {};
- socklen_t router_len = sizeof(router);
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_LEN(sizeof(int))];
+ } control = {};
+ struct iovec iov = {};
+ union sockaddr_union sa = {};
+ struct msghdr msg = {
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ struct in6_addr *gw;
unsigned lifetime;
ssize_t len;
+ int r, pref, stateful, buflen = 0;
assert(s);
assert(nd);
assert(nd->event);
r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0 || buflen <= 0)
- buflen = ICMP6_RECV_SIZE;
+ if (r < 0)
+ return -errno;
+ else if (buflen < 0)
+ /* This really should not happen */
+ return -EIO;
+
+ iov.iov_len = buflen;
- ra = malloc(buflen);
+ ra = malloc(iov.iov_len);
if (!ra)
return -ENOMEM;
- len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len);
+ iov.iov_base = ra;
+
+ len = recvmsg(fd, &msg, 0);
if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
+ return -errno;
+ } else if ((size_t)len < sizeof(struct nd_router_advert)) {
return 0;
- } else if (router_len != sizeof(router.in6) && router_len != 0) {
- log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len);
+ } else if (msg.msg_namelen == 0)
+ gw = NULL; /* only happens when running the test-suite over a socketpair */
+ else if (msg.msg_namelen != sizeof(sa.in6)) {
+ log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen);
+ return 0;
+ } else
+ gw = &sa.in6.sin6_addr;
+
+ assert(!(msg.msg_flags & MSG_CTRUNC));
+ assert(!(msg.msg_flags & MSG_TRUNC));
+
+ CMSG_FOREACH(cmsg, &msg) {
+ if (cmsg->cmsg_level == SOL_IPV6 &&
+ cmsg->cmsg_type == IPV6_HOPLIMIT &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ int hops = *(int*)CMSG_DATA(cmsg);
+
+ if (hops != 255) {
+ log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops);
+ return 0;
+ }
+
+ break;
+ }
+ }
+
+ if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) {
+ _cleanup_free_ char *addr = NULL;
+
+ (void)in_addr_to_string(AF_INET6, (const union in_addr_union*) gw, &addr);
+
+ log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring.", strna(addr));
return 0;
}
@@ -544,7 +600,7 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
}
if (nd->router_callback)
- nd->router_callback(nd, stateful, router_len != 0 ? &router.in6.sin6_addr : NULL, lifetime, pref, nd->userdata);
+ nd->router_callback(nd, stateful, gw, lifetime, pref, nd->userdata);
return 0;
}
@@ -552,8 +608,6 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
sd_ndisc *nd = userdata;
uint64_t time_now, next_timeout;
- struct ether_addr unset = { };
- struct ether_addr *addr = NULL;
int r;
assert(s);
@@ -567,10 +621,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
} else {
- if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
- addr = &nd->mac_addr;
-
- r = icmp6_send_router_solicitation(nd->fd, addr);
+ r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
if (r < 0)
log_ndisc(nd, "Error sending Router Solicitation");
else {
@@ -628,7 +679,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
assert(nd->event);
if (nd->state != NDISC_STATE_IDLE)
- return -EINVAL;
+ return -EBUSY;
if (nd->index < 1)
return -EINVAL;
diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c
index 94c31af3f3..69eff5116f 100644
--- a/src/libsystemd-network/test-acd.c
+++ b/src/libsystemd-network/test-acd.c
@@ -19,21 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
#include <unistd.h>
#include <linux/veth.h>
#include <net/if.h>
#include "sd-event.h"
-#include "sd-netlink.h"
#include "sd-ipv4acd.h"
+#include "sd-netlink.h"
-#include "util.h"
#include "event-util.h"
-#include "netlink-util.h"
#include "in-addr-util.h"
+#include "netlink-util.h"
+#include "util.h"
static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
assert_se(acd);
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 5b52c1cbb9..4478147a83 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -32,8 +32,8 @@
#include "dhcp-internal.h"
#include "dhcp-protocol.h"
#include "event-util.h"
-#include "util.h"
#include "fd-util.h"
+#include "util.h"
static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
@@ -223,7 +223,7 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const voi
static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
int res;
- res = dhcp_option_parse(dhcp, size, check_options, NULL);
+ res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
assert_se(res == DHCP_DISCOVER);
if (verbose)
@@ -390,7 +390,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
uint8_t *msg_bytes = (uint8_t *)request;
int res;
- res = dhcp_option_parse(request, size, check_options, NULL);
+ res = dhcp_option_parse(request, size, check_options, NULL, NULL);
assert_se(res == DHCP_REQUEST);
assert_se(xid == request->xid);
@@ -420,7 +420,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
uint8_t *msg_bytes = (uint8_t *)discover;
int res;
- res = dhcp_option_parse(discover, size, check_options, NULL);
+ res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
assert_se(res == DHCP_DISCOVER);
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 2d29e28f16..75d22c4df3 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -1,8 +1,8 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-#include <stdio.h>
-#include <stdbool.h>
#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
#include <string.h>
#include "alloc-util.h"
@@ -75,9 +75,8 @@ static const char *dhcp_type(int type) {
static void test_invalid_buffer_length(void) {
DHCPMessage message;
- assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
- assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL)
- == -EINVAL);
+ assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
+ assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
}
static void test_message_init(void) {
@@ -101,7 +100,7 @@ static void test_message_init(void) {
assert_se(magic[2] == 83);
assert_se(magic[3] == 99);
- assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0);
+ assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
}
static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
@@ -264,19 +263,12 @@ static void test_options(struct option_desc *desc) {
buflen = sizeof(DHCPMessage) + optlen;
if (!desc) {
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- NULL)) == -ENOMSG);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
} else if (desc->success) {
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) >= 0);
- assert_se(desc->pos == -1 && desc->filepos == -1 &&
- desc->snamepos == -1);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
+ assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
} else
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) < 0);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
if (verbose)
printf("DHCP type %s\n", dhcp_type(res));
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 1a5c8c4605..2b5f59e4d6 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -200,13 +200,11 @@ static void test_message_handler(void) {
static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
struct siphash state;
- uint64_t hash;
siphash24_init(&state, key);
client_id_hash_func(id, &state);
- siphash24_finalize((uint8_t*)&hash, &state);
- return hash;
+ return htole64(siphash24_finalize(&state));
}
static void test_client_id_hash(void) {
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 17ed6d58f3..9e05fde8f6 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -562,6 +562,7 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event,
sd_event *e = userdata;
sd_dhcp6_lease *lease;
struct in6_addr *addrs;
+ struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
char **domains;
assert_se(e);
@@ -590,6 +591,8 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event,
assert_se(sd_dhcp6_client_set_callback(client,
test_client_solicit_cb, e) >= 0);
+ assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
+
assert_se(sd_dhcp6_client_start(client) >= 0);
}
@@ -701,6 +704,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
static int test_client_solicit(sd_event *e) {
sd_dhcp6_client *client;
usec_t time_now = now(clock_boottime_or_monotonic());
+ struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
int val = true;
if (verbose)
@@ -729,6 +733,8 @@ static int test_client_solicit(sd_event *e) {
time_now + 2 * USEC_PER_SEC, 0,
test_hangcheck, NULL) >= 0);
+ assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
+
assert_se(sd_dhcp6_client_start(client) >= 0);
sd_event_loop(e);
diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c
index 91fab90cb0..c0c5d445eb 100644
--- a/src/libsystemd/sd-bus/bus-bloom.c
+++ b/src/libsystemd/sd-bus/bus-bloom.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "siphash24.h"
#include "bus-bloom.h"
+#include "siphash24.h"
+#include "util.h"
static inline void set_bit(uint64_t filter[], unsigned long b) {
filter[b >> 6] |= 1ULL << (b & 63);
@@ -45,7 +45,7 @@ static void bloom_add_data(
const void *data, /* Data to hash */
size_t n) { /* Size of data to hash in bytes */
- uint8_t h[8];
+ uint64_t h;
uint64_t m;
unsigned w, i, c = 0;
unsigned hash_index;
@@ -72,11 +72,11 @@ static void bloom_add_data(
for (d = 0; d < w; d++) {
if (c <= 0) {
- siphash24(h, data, n, hash_keys[hash_index++].bytes);
+ h = siphash24(data, n, hash_keys[hash_index++].bytes);
c += 8;
}
- p = (p << 8ULL) | (uint64_t) h[8 - c];
+ p = (p << 8ULL) | (uint64_t) ((uint8_t *)&h)[8 - c];
c--;
}
diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h
index a9350d7f51..38892044f1 100644
--- a/src/libsystemd/sd-bus/bus-bloom.h
+++ b/src/libsystemd/sd-bus/bus-bloom.h
@@ -22,6 +22,7 @@
***/
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
/*
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index 52f8dfd3be..8d486fcbbd 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -22,8 +22,9 @@
#include <errno.h>
#include "sd-bus.h"
-#include "bus-error.h"
+
#include "bus-common-errors.h"
+#include "bus-error.h"
BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT, ENOENT),
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 589a90bbff..7da6ba9903 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <fcntl.h>
+#include <unistd.h>
#include "bus-container.h"
#include "bus-internal.h"
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index ddd3a55b6c..94251fe87c 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -23,8 +23,8 @@
#include <valgrind/memcheck.h>
#endif
-#include <stddef.h>
#include <errno.h>
+#include <stddef.h>
#include "sd-bus.h"
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index 5009ca8e61..e01b075832 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "bus-match.h"
int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h
index d2522edeba..71e56991fa 100644
--- a/src/libsystemd/sd-bus/bus-dump.h
+++ b/src/libsystemd/sd-bus/bus-dump.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdbool.h>
+#include <stdio.h>
#include "sd-bus.h"
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index 239d7245e6..404eaa3c89 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -29,10 +29,10 @@
#include "sd-bus.h"
#include "alloc-util.h"
+#include "bus-error.h"
#include "errno-list.h"
#include "string-util.h"
#include "util.h"
-#include "bus-error.h"
BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES),
diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h
index fb0199c948..d7fd8612d0 100644
--- a/src/libsystemd/sd-bus/bus-error.h
+++ b/src/libsystemd/sd-bus/bus-error.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include "sd-bus.h"
+
#include "macro.h"
bool bus_error_is_dirty(sd_bus_error *e);
diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c
index 402d43d66d..ec027590b2 100644
--- a/src/libsystemd/sd-bus/bus-gvariant.c
+++ b/src/libsystemd/sd-bus/bus-gvariant.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-type.h"
#include "bus-gvariant.h"
#include "bus-signature.h"
+#include "bus-type.h"
int bus_gvariant_get_size(const char *signature) {
const char *p;
diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h
index 1914e6cb8b..57c2430ee8 100644
--- a/src/libsystemd/sd-bus/bus-introspect.h
+++ b/src/libsystemd/sd-bus/bus-introspect.h
@@ -24,6 +24,7 @@
#include <stdio.h>
#include "sd-bus.h"
+
#include "set.h"
struct introspect {
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 8c472626a8..303e49fa84 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -23,6 +23,7 @@
#include "bus-internal.h"
#include "bus-introspect.h"
#include "bus-message.h"
+#include "bus-objects.h"
#include "bus-signature.h"
#include "bus-slot.h"
#include "bus-type.h"
@@ -30,7 +31,6 @@
#include "set.h"
#include "string-util.h"
#include "strv.h"
-#include "bus-objects.h"
static int node_vtable_get_userdata(
sd_bus *bus,
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index 550bad27ba..e405a04c53 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -24,8 +24,8 @@
#include "alloc-util.h"
#include "bus-control.h"
#include "bus-objects.h"
-#include "string-util.h"
#include "bus-slot.h"
+#include "string-util.h"
sd_bus_slot *bus_slot_allocate(
sd_bus *bus,
diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h
index 23a15e4d02..c997e58f9a 100644
--- a/src/libsystemd/sd-bus/bus-slot.h
+++ b/src/libsystemd/sd-bus/bus-slot.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "bus-internal.h"
sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata);
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index a8d79b01b0..99780c8cce 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -20,12 +20,12 @@
***/
#include <endian.h>
-#include <stdlib.h>
-#include <unistd.h>
#include <netdb.h>
#include <poll.h>
-#include <sys/mman.h>
#include <pthread.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include "sd-bus.h"
@@ -46,10 +46,10 @@
#include "cgroup-util.h"
#include "def.h"
#include "fd-util.h"
+#include "hexdecoct.h"
#include "hostname-util.h"
#include "macro.h"
#include "missing.h"
-#include "hexdecoct.h"
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 767aef63ff..f20eced4ac 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include "sd-bus.h"
@@ -31,11 +31,11 @@
#include "bus-internal.h"
#include "bus-match.h"
#include "bus-util.h"
+#include "fd-util.h"
#include "formats-util.h"
#include "log.h"
#include "macro.h"
#include "util.h"
-#include "fd-util.h"
static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index 580117165a..bd0101af9e 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -20,6 +20,7 @@
***/
#include "sd-bus.h"
+
#include "bus-dump.h"
#include "bus-util.h"
#include "cgroup-util.h"
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index 5753c04b0e..9d6c221eb0 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -20,10 +20,11 @@
***/
#include "sd-bus.h"
+
+#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "errno-list.h"
-#include "bus-common-errors.h"
static void test_error(void) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
index f39dedeb24..26ba16d119 100644
--- a/src/libsystemd/sd-bus/test-bus-introspect.c
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
#include "bus-introspect.h"
+#include "log.h"
static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
return -EINVAL;
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index 0747d6a37c..0a6093e78b 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <math.h>
+#include <stdlib.h>
#ifdef HAVE_GLIB
#include <gio/gio.h>
@@ -38,8 +38,8 @@
#include "bus-message.h"
#include "bus-util.h"
#include "fd-util.h"
-#include "log.h"
#include "hexdecoct.h"
+#include "log.h"
#include "util.h"
static void test_bus_path_encode_unique(void) {
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
index 75ea28371b..94896c196a 100644
--- a/src/libsystemd/sd-bus/test-bus-match.c
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -19,13 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
-#include "macro.h"
-
#include "bus-match.h"
#include "bus-message.h"
-#include "bus-util.h"
#include "bus-slot.h"
+#include "bus-util.h"
+#include "log.h"
+#include "macro.h"
static bool mask[32];
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index 5bc72e2355..edd63f9ea7 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <pthread.h>
+#include <stdlib.h>
#include "sd-bus.h"
diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c
index 92a810a7d8..949d16e6e9 100644
--- a/src/libsystemd/sd-bus/test-bus-signature.c
+++ b/src/libsystemd/sd-bus/test-bus-signature.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "string-util.h"
-#include "log.h"
-#include "bus-signature.h"
#include "bus-internal.h"
+#include "bus-signature.h"
+#include "log.h"
+#include "string-util.h"
int main(int argc, char *argv[]) {
char prefix[256];
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
index ff8df61a9e..1cf8416fa4 100644
--- a/src/libsystemd/sd-bus/test-bus-zero-copy.c
+++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c
@@ -27,11 +27,11 @@
#include "bus-dump.h"
#include "bus-kernel.h"
#include "bus-message.h"
+#include "fd-util.h"
#include "log.h"
#include "memfd-util.h"
#include "string-util.h"
#include "util.h"
-#include "fd-util.h"
#define FIRST_ARRAY 17
#define SECOND_ARRAY 33
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index ee4886700e..3191b458d1 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -34,6 +34,7 @@
#include "macro.h"
#include "missing.h"
#include "prioq.h"
+#include "process-util.h"
#include "set.h"
#include "signal-util.h"
#include "string-util.h"
@@ -415,11 +416,9 @@ _public_ int sd_event_new(sd_event** ret) {
e->original_pid = getpid();
e->perturb = USEC_INFINITY;
- e->pending = prioq_new(pending_prioq_compare);
- if (!e->pending) {
- r = -ENOMEM;
+ r = prioq_ensure_allocated(&e->pending, pending_prioq_compare);
+ if (r < 0)
goto fail;
- }
e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (e->epoll_fd < 0) {
@@ -436,7 +435,9 @@ fail:
}
_public_ sd_event* sd_event_ref(sd_event *e) {
- assert_return(e, NULL);
+
+ if (!e)
+ return NULL;
assert(e->n_ref >= 1);
e->n_ref++;
@@ -808,7 +809,7 @@ static void source_disconnect(sd_event_source *s) {
s->event->n_enabled_child_sources--;
}
- (void) hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
+ (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
}
@@ -1049,17 +1050,13 @@ _public_ int sd_event_add_time(
d = event_get_clock_data(e, type);
assert(d);
- if (!d->earliest) {
- d->earliest = prioq_new(earliest_time_prioq_compare);
- if (!d->earliest)
- return -ENOMEM;
- }
+ r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
+ if (r < 0)
+ return r;
- if (!d->latest) {
- d->latest = prioq_new(latest_time_prioq_compare);
- if (!d->latest)
- return -ENOMEM;
- }
+ r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
+ if (r < 0)
+ return r;
if (d->fd < 0) {
r = event_setup_timer_fd(e, d, clock);
@@ -1188,7 +1185,7 @@ _public_ int sd_event_add_child(
if (r < 0)
return r;
- if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
+ if (hashmap_contains(e->child_sources, PID_TO_PTR(pid)))
return -EBUSY;
s = source_new(e, !ret, SOURCE_CHILD);
@@ -1201,7 +1198,7 @@ _public_ int sd_event_add_child(
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
- r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s);
+ r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
if (r < 0) {
source_free(s);
return r;
@@ -1310,11 +1307,9 @@ _public_ int sd_event_add_exit(
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
- if (!e->exit) {
- e->exit = prioq_new(exit_prioq_compare);
- if (!e->exit)
- return -ENOMEM;
- }
+ r = prioq_ensure_allocated(&e->exit, exit_prioq_compare);
+ if (r < 0)
+ return r;
s = source_new(e, !ret, SOURCE_EXIT);
if (!s)
@@ -1338,7 +1333,9 @@ _public_ int sd_event_add_exit(
}
_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) {
- assert_return(s, NULL);
+
+ if (!s)
+ return NULL;
assert(s->n_ref >= 1);
s->n_ref++;
@@ -2432,7 +2429,9 @@ _public_ int sd_event_prepare(sd_event *e) {
e->iteration++;
+ e->state = SD_EVENT_PREPARING;
r = event_prepare(e);
+ e->state = SD_EVENT_INITIAL;
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index c1a3b49483..9417a8d1d1 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -158,11 +158,22 @@ static int exit_handler(sd_event_source *s, void *userdata) {
return 3;
}
+static bool got_post = false;
+
+static int post_handler(sd_event_source *s, void *userdata) {
+ log_info("got post handler");
+
+ got_post = true;
+
+ return 2;
+}
+
static void test_basic(void) {
sd_event *e = NULL;
sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
static const char ch = 'x';
int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
+ uint64_t event_now;
assert_se(pipe(a) >= 0);
assert_se(pipe(b) >= 0);
@@ -170,6 +181,7 @@ static void test_basic(void) {
assert_se(pipe(k) >= 0);
assert_se(sd_event_default(&e) >= 0);
+ assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_set_watchdog(e, true) >= 0);
@@ -230,10 +242,14 @@ static void test_basic(void) {
sd_event_source_unref(y);
do_quit = true;
- assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
+ assert_se(sd_event_add_post(e, NULL, post_handler, NULL) >= 0);
+ assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
+ assert_se(sd_event_source_set_time(z, event_now + 200 * USEC_PER_MSEC) >= 0);
assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
assert_se(sd_event_loop(e) >= 0);
+ assert_se(got_post);
+ assert_se(got_exit);
sd_event_source_unref(z);
sd_event_source_unref(q);
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 1e17ea6a06..c12bb1e20b 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -26,9 +26,9 @@
#include "sd-id128.h"
#include "fd-util.h"
+#include "hexdecoct.h"
#include "io-util.h"
#include "macro.h"
-#include "hexdecoct.h"
#include "random-util.h"
#include "util.h"
diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c
index a00865b56b..d431ba4be4 100644
--- a/src/libsystemd/sd-netlink/local-addresses.c
+++ b/src/libsystemd/sd-netlink/local-addresses.c
@@ -23,9 +23,9 @@
#include "sd-netlink.h"
#include "alloc-util.h"
-#include "netlink-util.h"
-#include "macro.h"
#include "local-addresses.h"
+#include "macro.h"
+#include "netlink-util.h"
static int address_compare(const void *_a, const void *_b) {
const struct local_address *a = _a, *b = _b;
diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h
index 5d0f11a2c1..74d4f25534 100644
--- a/src/libsystemd/sd-netlink/local-addresses.h
+++ b/src/libsystemd/sd-netlink/local-addresses.h
@@ -23,6 +23,7 @@
#include "sd-netlink.h"
+
#include "in-addr-util.h"
struct local_address {
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
index bf7c641541..9e636a0b53 100644
--- a/src/libsystemd/sd-netlink/netlink-types.h
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -21,6 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "macro.h"
+
enum {
NETLINK_TYPE_UNSPEC,
NETLINK_TYPE_U8, /* NLA_U8 */
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 6f9fd2993b..95690b7ff1 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -21,8 +21,8 @@
#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
+#include "netlink-util.h"
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c
index 7180175970..0b53297ab8 100644
--- a/src/libsystemd/sd-netlink/test-local-addresses.c
+++ b/src/libsystemd/sd-netlink/test-local-addresses.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "af-list.h"
#include "alloc-util.h"
#include "in-addr-util.h"
#include "local-addresses.h"
-#include "af-list.h"
static void print_local_addresses(struct local_address *a, unsigned n) {
unsigned i;
diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c
index 381397cc52..9e52db3b3d 100644
--- a/src/libsystemd/sd-utf8/sd-utf8.c
+++ b/src/libsystemd/sd-utf8/sd-utf8.c
@@ -21,8 +21,8 @@
#include "sd-utf8.h"
-#include "util.h"
#include "utf8.h"
+#include "util.h"
_public_ const char *sd_utf8_is_valid(const char *s) {
assert_return(s, NULL);
diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
index 5f50496291..52c5075110 100644
--- a/src/libudev/libudev-private.h
+++ b/src/libudev/libudev-private.h
@@ -21,8 +21,8 @@
#define _LIBUDEV_PRIVATE_H_
#include <signal.h>
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include "libudev.h"
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index 58410b1b8f..e3dffa6925 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -18,11 +18,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
#include <sys/inotify.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h
index 93e9ed02eb..1f55759798 100644
--- a/src/login/logind-acl.h
+++ b/src/login/logind-acl.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdbool.h>
+#include <sys/types.h>
#include "libudev.h"
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index e9b424b5f6..63c279cde7 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -35,8 +35,8 @@ typedef enum HandleAction {
_HANDLE_ACTION_INVALID = -1
} HandleAction;
-#include "logind.h"
#include "logind-inhibit.h"
+#include "logind.h"
int manager_handle_action(
Manager *m,
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index b3f30c8dc9..36cdbbe0f9 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/ioctl.h>
#include <fcntl.h>
#include <pwd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
#include <linux/vt.h>
#include "alloc-util.h"
@@ -98,15 +98,16 @@ int manager_add_session(Manager *m, const char *id, Session **_session) {
int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
User *u;
+ int r;
assert(m);
assert(name);
u = hashmap_get(m->users, UID_TO_PTR(uid));
if (!u) {
- u = user_new(m, uid, gid, name);
- if (!u)
- return -ENOMEM;
+ r = user_new(&u, m, uid, gid, name);
+ if (r < 0)
+ return r;
}
if (_user)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 7890d68aa0..e507a19aef 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -308,8 +308,10 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd
r = sd_bus_message_read(message, "u", &pid);
if (r < 0)
return r;
+ if (pid < 0)
+ return -EINVAL;
- if (pid <= 0) {
+ if (pid == 0) {
r = manager_get_session_from_creds(m, message, NULL, error, &session);
if (r < 0)
return r;
@@ -369,8 +371,10 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu
r = sd_bus_message_read(message, "u", &pid);
if (r < 0)
return r;
+ if (pid < 0)
+ return -EINVAL;
- if (pid <= 0) {
+ if (pid == 0) {
r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
if (r < 0)
return r;
@@ -573,12 +577,14 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu
static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
- uint32_t uid, leader, audit_id = 0;
+ uint32_t audit_id = 0;
_cleanup_free_ char *id = NULL;
Session *session = NULL;
Manager *m = userdata;
User *user = NULL;
Seat *seat = NULL;
+ pid_t leader;
+ uid_t uid;
int remote;
uint32_t vtnr = 0;
SessionType t;
@@ -588,11 +594,16 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
assert(message);
assert(m);
+ assert_cc(sizeof(pid_t) == sizeof(uint32_t));
+ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+
r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
if (r < 0)
return r;
- if (leader == 1)
+ if (!uid_is_valid(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
+ if (leader < 0 || leader == 1)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (isempty(type))
@@ -684,7 +695,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
c = SESSION_USER;
}
- if (leader <= 0) {
+ if (leader == 0) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
@@ -1093,7 +1104,9 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r < 0)
return r;
- }
+
+ } else if (!uid_is_valid(uid))
+ return -EINVAL;
errno = 0;
pw = getpwuid(uid);
@@ -2607,11 +2620,8 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
session = hashmap_get(m->session_units, unit);
- if (session) {
-
- if (streq_ptr(path, session->scope_job))
- session->scope_job = mfree(session->scope_job);
-
+ if (session && streq_ptr(path, session->scope_job)) {
+ session->scope_job = mfree(session->scope_job);
session_jobs_reply(session, unit, result);
session_save(session);
@@ -2620,7 +2630,9 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
user = hashmap_get(m->user_units, unit);
- if (user) {
+ if (user &&
+ (streq_ptr(path, user->service_job) ||
+ streq_ptr(path, user->slice_job))) {
if (streq_ptr(path, user->service_job))
user->service_job = mfree(user->service_job);
@@ -2740,13 +2752,101 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
l);
}
+int manager_start_slice(
+ Manager *manager,
+ const char *slice,
+ const char *description,
+ const char *after,
+ const char *after2,
+ uint64_t tasks_max,
+ sd_bus_error *error,
+ char **job) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ int r;
+
+ assert(manager);
+ assert(slice);
+
+ r = sd_bus_message_new_method_call(
+ manager->bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0)
+ return r;
+
+ if (!isempty(description)) {
+ r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
+ if (r < 0)
+ return r;
+ }
+
+ if (!isempty(after)) {
+ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
+ if (r < 0)
+ return r;
+ }
+
+ if (!isempty(after2)) {
+ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call(manager->bus, m, 0, error, &reply);
+ if (r < 0)
+ return r;
+
+ if (job) {
+ const char *j;
+ char *copy;
+
+ r = sd_bus_message_read(reply, "o", &j);
+ if (r < 0)
+ return r;
+
+ copy = strdup(j);
+ if (!copy)
+ return -ENOMEM;
+
+ *job = copy;
+ }
+
+ return 1;
+}
+
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
- const char *after, const char *after2,
+ const char *after,
+ const char *after2,
+ uint64_t tasks_max,
sd_bus_error *error,
char **job) {
@@ -2814,6 +2914,10 @@ int manager_start_scope(
if (r < 0)
return r;
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
@@ -2859,7 +2963,7 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error,
"StartUnit",
error,
&reply,
- "ss", unit, "fail");
+ "ss", unit, "replace");
if (r < 0)
return r;
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 9218d098e0..8552c464cc 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -34,3 +34,4 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
+Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 1d561a6f8a..9f03a7b31e 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -36,7 +36,6 @@
#include "bus-util.h"
#include "escape.h"
#include "fd-util.h"
-#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
#include "io-util.h"
@@ -513,25 +512,31 @@ static int session_start_scope(Session *s) {
assert(s);
assert(s->user);
- assert(s->user->slice);
if (!s->scope) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *description = NULL;
char *scope, *job = NULL;
-
- description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
- if (!description)
- return log_oom();
+ const char *description;
scope = strjoin("session-", s->id, ".scope", NULL);
if (!scope)
return log_oom();
- r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
+ description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
+
+ r = manager_start_scope(
+ s->manager,
+ scope,
+ s->leader,
+ s->user->slice,
+ description,
+ "systemd-logind.service",
+ "systemd-user-sessions.service",
+ (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
+ &error,
+ &job);
if (r < 0) {
- log_error("Failed to start session scope %s: %s %s",
- scope, bus_error_message(&error, r), error.name);
+ log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
free(scope);
return r;
} else {
@@ -543,7 +548,7 @@ static int session_start_scope(Session *s) {
}
if (s->scope)
- hashmap_put(s->manager->session_units, s->scope, s);
+ (void) hashmap_put(s->manager->session_units, s->scope, s);
return 0;
}
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index d054c33cec..d27407fc92 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -25,8 +25,8 @@ typedef struct Session Session;
typedef enum KillWho KillWho;
#include "list.h"
-#include "logind-user.h"
#include "login-util.h"
+#include "logind-user.h"
typedef enum SessionState {
SESSION_OPENING, /* Session scope is being created */
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 56bc5a010c..778f19b50d 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "clean-ipc.h"
@@ -44,47 +45,68 @@
#include "rm-rf.h"
#include "smack-util.h"
#include "special.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "unit-name.h"
#include "user-util.h"
#include "util.h"
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
- User *u;
+int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) {
+ _cleanup_(user_freep) User *u = NULL;
+ char lu[DECIMAL_STR_MAX(uid_t) + 1];
+ int r;
+ assert(out);
assert(m);
assert(name);
u = new0(User, 1);
if (!u)
- return NULL;
+ return -ENOMEM;
+
+ u->manager = m;
+ u->uid = uid;
+ u->gid = gid;
+ xsprintf(lu, UID_FMT, uid);
u->name = strdup(name);
if (!u->name)
- goto fail;
+ return -ENOMEM;
if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
- goto fail;
+ return -ENOMEM;
- if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
- goto fail;
+ if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0)
+ return -ENOMEM;
- u->manager = m;
- u->uid = uid;
- u->gid = gid;
+ r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
+ if (r < 0)
+ return r;
- return u;
+ r = unit_name_build("user", lu, ".service", &u->service);
+ if (r < 0)
+ return r;
-fail:
- free(u->state_file);
- free(u->name);
- free(u);
+ r = hashmap_put(m->users, UID_TO_PTR(uid), u);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(m->user_units, u->slice, u);
+ if (r < 0)
+ return r;
- return NULL;
+ r = hashmap_put(m->user_units, u->service, u);
+ if (r < 0)
+ return r;
+
+ *out = u;
+ u = NULL;
+ return 0;
}
-void user_free(User *u) {
- assert(u);
+User *user_free(User *u) {
+ if (!u)
+ return NULL;
if (u->in_gc_queue)
LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
@@ -92,26 +114,24 @@ void user_free(User *u) {
while (u->sessions)
session_free(u->sessions);
- if (u->slice) {
- hashmap_remove(u->manager->user_units, u->slice);
- free(u->slice);
- }
+ if (u->service)
+ hashmap_remove_value(u->manager->user_units, u->service, u);
- if (u->service) {
- hashmap_remove(u->manager->user_units, u->service);
- free(u->service);
- }
+ if (u->slice)
+ hashmap_remove_value(u->manager->user_units, u->slice, u);
- free(u->slice_job);
- free(u->service_job);
+ hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u);
- free(u->runtime_path);
+ u->slice_job = mfree(u->slice_job);
+ u->service_job = mfree(u->service_job);
- hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
+ u->service = mfree(u->service);
+ u->slice = mfree(u->slice);
+ u->runtime_path = mfree(u->runtime_path);
+ u->state_file = mfree(u->state_file);
+ u->name = mfree(u->name);
- free(u->name);
- free(u->state_file);
- free(u);
+ return mfree(u);
}
static int user_save_internal(User *u) {
@@ -139,16 +159,13 @@ static int user_save_internal(User *u) {
u->name,
user_state_to_string(user_get_state(u)));
+ /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
if (u->runtime_path)
fprintf(f, "RUNTIME=%s\n", u->runtime_path);
- if (u->service)
- fprintf(f, "SERVICE=%s\n", u->service);
if (u->service_job)
fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
- if (u->slice)
- fprintf(f, "SLICE=%s\n", u->slice);
if (u->slice_job)
fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
@@ -286,10 +303,7 @@ int user_load(User *u) {
assert(u);
r = parse_env_file(u->state_file, NEWLINE,
- "RUNTIME", &u->runtime_path,
- "SERVICE", &u->service,
"SERVICE_JOB", &u->service_job,
- "SLICE", &u->slice,
"SLICE_JOB", &u->slice_job,
"DISPLAY", &display,
"REALTIME", &realtime,
@@ -325,7 +339,6 @@ int user_load(User *u) {
}
static int user_mkdir_runtime_path(User *u) {
- char *p;
int r;
assert(u);
@@ -334,16 +347,10 @@ static int user_mkdir_runtime_path(User *u) {
if (r < 0)
return log_error_errno(r, "Failed to create /run/user: %m");
- if (!u->runtime_path) {
- if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
- return log_oom();
- } else
- p = u->runtime_path;
-
- if (path_is_mount_point(p, 0) <= 0) {
+ if (path_is_mount_point(u->runtime_path, 0) <= 0) {
_cleanup_free_ char *t = NULL;
- (void) mkdir_label(p, 0700);
+ (void) mkdir_label(u->runtime_path, 0700);
if (mac_smack_use())
r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
@@ -354,10 +361,10 @@ static int user_mkdir_runtime_path(User *u) {
goto fail;
}
- r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
+ r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t);
if (r < 0) {
if (errno != EPERM) {
- r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
+ r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
goto fail;
}
@@ -365,62 +372,54 @@ static int user_mkdir_runtime_path(User *u) {
* CAP_SYS_ADMIN-less container? In this case,
* just use a normal directory. */
- r = chmod_and_chown(p, 0700, u->uid, u->gid);
+ r = chmod_and_chown(u->runtime_path, 0700, u->uid, u->gid);
if (r < 0) {
log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
goto fail;
}
}
- r = label_fix(p, false, false);
+ r = label_fix(u->runtime_path, false, false);
if (r < 0)
- log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p);
+ log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", u->runtime_path);
}
- u->runtime_path = p;
return 0;
fail:
- if (p) {
- /* Try to clean up, but ignore errors */
- (void) rmdir(p);
- free(p);
- }
-
- u->runtime_path = NULL;
+ /* Try to clean up, but ignore errors */
+ (void) rmdir(u->runtime_path);
return r;
}
static int user_start_slice(User *u) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *description;
char *job;
int r;
assert(u);
- if (!u->slice) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
- sprintf(lu, UID_FMT, u->uid);
-
- r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
- if (r < 0)
- return r;
-
- r = manager_start_unit(u->manager, slice, &error, &job);
- if (r < 0) {
- log_error("Failed to start user slice: %s", bus_error_message(&error, r));
- free(slice);
- } else {
- u->slice = slice;
-
- free(u->slice_job);
- u->slice_job = job;
- }
+ u->slice_job = mfree(u->slice_job);
+ description = strjoina("User Slice of ", u->name);
+
+ r = manager_start_slice(
+ u->manager,
+ u->slice,
+ description,
+ "systemd-logind.service",
+ "systemd-user-sessions.service",
+ u->manager->user_tasks_max,
+ &error,
+ &job);
+ if (r < 0) {
+ /* we don't fail due to this, let's try to continue */
+ if (!sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
+ log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", u->slice, bus_error_message(&error, r), error.name);
+ } else {
+ u->slice_job = job;
}
- if (u->slice)
- hashmap_put(u->manager->user_units, u->slice, u);
-
return 0;
}
@@ -431,29 +430,20 @@ static int user_start_service(User *u) {
assert(u);
- if (!u->service) {
- char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
- sprintf(lu, UID_FMT, u->uid);
-
- r = unit_name_build("user", lu, ".service", &service);
- if (r < 0)
- return log_error_errno(r, "Failed to build service name: %m");
-
- r = manager_start_unit(u->manager, service, &error, &job);
- if (r < 0) {
- log_error("Failed to start user service: %s", bus_error_message(&error, r));
- free(service);
- } else {
- u->service = service;
+ u->service_job = mfree(u->service_job);
- free(u->service_job);
- u->service_job = job;
- }
+ r = manager_start_unit(
+ u->manager,
+ u->service,
+ &error,
+ &job);
+ if (r < 0) {
+ /* we don't fail due to this, let's try to continue */
+ log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r));
+ } else {
+ u->service_job = job;
}
- if (u->service)
- hashmap_put(u->manager->user_units, u->service, u);
-
return 0;
}
@@ -462,15 +452,32 @@ int user_start(User *u) {
assert(u);
- if (u->started)
+ if (u->started && !u->stopping)
return 0;
- log_debug("New user %s logged in.", u->name);
-
- /* Make XDG_RUNTIME_DIR */
- r = user_mkdir_runtime_path(u);
- if (r < 0)
- return r;
+ /*
+ * If u->stopping is set, the user is marked for removal and the slice
+ * and service stop-jobs are queued. We have to clear that flag before
+ * queing the start-jobs again. If they succeed, the user object can be
+ * re-used just fine (pid1 takes care of job-ordering and proper
+ * restart), but if they fail, we want to force another user_stop() so
+ * possibly pending units are stopped.
+ * Note that we don't clear u->started, as we have no clue what state
+ * the user is in on failure here. Hence, we pretend the user is
+ * running so it will be properly taken down by GC. However, we clearly
+ * return an error from user_start() in that case, so no further
+ * reference to the user is taken.
+ */
+ u->stopping = false;
+
+ if (!u->started) {
+ log_debug("New user %s logged in.", u->name);
+
+ /* Make XDG_RUNTIME_DIR */
+ r = user_mkdir_runtime_path(u);
+ if (r < 0)
+ return r;
+ }
/* Create cgroup */
r = user_start_slice(u);
@@ -488,16 +495,16 @@ int user_start(User *u) {
if (r < 0)
return r;
- if (!dual_timestamp_is_set(&u->timestamp))
- dual_timestamp_get(&u->timestamp);
-
- u->started = true;
+ if (!u->started) {
+ if (!dual_timestamp_is_set(&u->timestamp))
+ dual_timestamp_get(&u->timestamp);
+ user_send_signal(u, true);
+ u->started = true;
+ }
/* Save new user data */
user_save(u);
- user_send_signal(u, true);
-
return 0;
}
@@ -508,9 +515,6 @@ static int user_stop_slice(User *u) {
assert(u);
- if (!u->slice)
- return 0;
-
r = manager_stop_unit(u->manager, u->slice, &error, &job);
if (r < 0) {
log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
@@ -530,9 +534,6 @@ static int user_stop_service(User *u) {
assert(u);
- if (!u->service)
- return 0;
-
r = manager_stop_unit(u->manager, u->service, &error, &job);
if (r < 0) {
log_error("Failed to stop user service: %s", bus_error_message(&error, r));
@@ -550,9 +551,6 @@ static int user_remove_runtime_path(User *u) {
assert(u);
- if (!u->runtime_path)
- return 0;
-
r = rm_rf(u->runtime_path, 0);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
@@ -568,8 +566,6 @@ static int user_remove_runtime_path(User *u) {
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
- u->runtime_path = mfree(u->runtime_path);
-
return r;
}
@@ -761,9 +757,6 @@ UserState user_get_state(User *u) {
int user_kill(User *u, int signo) {
assert(u);
- if (!u->slice)
- return -ESRCH;
-
return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
}
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
index 722247806b..de99cf47b4 100644
--- a/src/login/logind-user.h
+++ b/src/login/logind-user.h
@@ -39,16 +39,13 @@ typedef enum UserState {
struct User {
Manager *manager;
-
uid_t uid;
gid_t gid;
char *name;
-
char *state_file;
char *runtime_path;
-
- char *service;
char *slice;
+ char *service;
char *service_job;
char *slice_job;
@@ -65,8 +62,11 @@ struct User {
LIST_FIELDS(User, gc_queue);
};
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
-void user_free(User *u);
+int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name);
+User *user_free(User *u);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(User *, user_free);
+
bool user_check_gc(User *u, bool drop_not_started);
void user_add_to_gc_queue(User *u);
int user_start(User *u);
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 3e7a935a34..3bd61a81fd 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -20,9 +20,9 @@
***/
#include <errno.h>
+#include <pwd.h>
#include <string.h>
#include <unistd.h>
-#include <pwd.h>
#include "sd-messages.h"
diff --git a/src/login/logind.c b/src/login/logind.c
index be6bbe5b5c..7b41174c64 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -70,6 +70,7 @@ static Manager *manager_new(void) {
m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
+ m->user_tasks_max = UINT64_C(4096);
m->devices = hashmap_new(&string_hash_ops);
m->seats = hashmap_new(&string_hash_ops);
diff --git a/src/login/logind.conf b/src/login/logind.conf
index 6df6f04c77..81f6695434 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf
@@ -32,3 +32,4 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
+#UserTasksMax=4096
diff --git a/src/login/logind.h b/src/login/logind.h
index 44e05d8b01..f34544e64c 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -134,6 +134,7 @@ struct Manager {
sd_event_source *lid_switch_ignore_event_source;
size_t runtime_dir_size;
+ uint64_t user_tasks_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
@@ -171,7 +172,8 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
+int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 0d61f528db..ed4f7c726f 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -267,29 +267,21 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_SERVICE, (const void**) &service);
if (streq_ptr(service, "systemd-user")) {
- _cleanup_free_ char *p = NULL, *rt = NULL;
+ _cleanup_free_ char *rt = NULL;
- if (asprintf(&p, "/run/systemd/users/"UID_FMT, pw->pw_uid) < 0)
+ if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0)
return PAM_BUF_ERR;
- r = parse_env_file(p, NEWLINE,
- "RUNTIME", &rt,
- NULL);
- if (r < 0 && r != -ENOENT)
- return PAM_SESSION_ERR;
-
- if (rt) {
- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
- return r;
- }
-
- r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
- if (r != PAM_SUCCESS)
- return r;
+ r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
+ return r;
}
+ r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
+ if (r != PAM_SUCCESS)
+ return r;
+
return PAM_SUCCESS;
}
@@ -501,7 +493,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return PAM_SESSION_ERR;
}
- r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
+ r = pam_set_data(handle, "systemd.session-fd", FD_TO_PTR(session_fd), NULL);
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
safe_close(session_fd);
diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c
index 4c4275d124..ac327f71fb 100644
--- a/src/login/test-login-shared.c
+++ b/src/login/test-login-shared.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
#include "login-util.h"
+#include "macro.h"
static void test_session_id_valid(void) {
assert_se(session_id_valid("c1"));
diff --git a/src/login/test-login-tables.c b/src/login/test-login-tables.c
index a4196bf14b..4fbc893a9a 100644
--- a/src/login/test-login-tables.c
+++ b/src/login/test-login-tables.c
@@ -19,7 +19,6 @@
#include "logind-action.h"
#include "logind-session.h"
-
#include "test-tables.h"
int main(int argc, char **argv) {
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index f1165ea09c..d805bcfdca 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -26,8 +26,8 @@
#include "log.h"
#include "machine-id-setup.h"
-#include "util.h"
#include "path-util.h"
+#include "util.h"
static char *arg_root = NULL;
static bool arg_commit = false;
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 196bc4b8f4..6b1fae2769 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -29,6 +29,7 @@
#include "bus-error.h"
#include "bus-util.h"
#include "escape.h"
+#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
@@ -37,12 +38,12 @@
#include "machine.h"
#include "mkdir.h"
#include "parse-util.h"
+#include "process-util.h"
#include "special.h"
#include "string-table.h"
#include "terminal-util.h"
#include "unit-name.h"
#include "util.h"
-#include "extract-word.h"
Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
Machine *m;
@@ -105,7 +106,7 @@ void machine_free(Machine *m) {
m->manager->host_machine = NULL;
if (m->leader > 0)
- (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
+ (void) hashmap_remove_value(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
sd_bus_message_unref(m->create_message);
@@ -401,7 +402,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
if (m->started)
return 0;
- r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
+ r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
if (r < 0)
return r;
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 7827f063c1..961767c4a9 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -199,6 +199,9 @@ static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
+ if (pid < 0)
+ return -EINVAL;
+
if (pid == 0) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
@@ -1505,7 +1508,7 @@ int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
assert(pid >= 1);
assert(machine);
- mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
+ mm = hashmap_get(m->machine_leaders, PID_TO_PTR(pid));
if (!mm) {
_cleanup_free_ char *unit = NULL;
diff --git a/src/machine/machined.h b/src/machine/machined.h
index dac7a29ed1..bc5d4abb80 100644
--- a/src/machine/machined.h
+++ b/src/machine/machined.h
@@ -31,9 +31,9 @@
typedef struct Manager Manager;
-#include "machine.h"
-#include "machine-dbus.h"
#include "image-dbus.h"
+#include "machine-dbus.h"
+#include "machine.h"
struct Manager {
sd_event *event;
diff --git a/src/machine/test-machine-tables.c b/src/machine/test-machine-tables.c
index 4aae426050..f851a4d37d 100644
--- a/src/machine/test-machine-tables.c
+++ b/src/machine/test-machine-tables.c
@@ -18,7 +18,6 @@
***/
#include "machine.h"
-
#include "test-tables.h"
int main(int argc, char **argv) {
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 446b048ef1..6fcb3050c7 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -36,7 +36,6 @@
#include "lldp.h"
#include "local-addresses.h"
#include "locale-util.h"
-#include "locale-util.h"
#include "netlink-util.h"
#include "pager.h"
#include "parse-util.h"
diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h
index e6207ccce6..7f5bdf1d2f 100644
--- a/src/network/networkd-address-pool.h
+++ b/src/network/networkd-address-pool.h
@@ -23,6 +23,7 @@
typedef struct AddressPool AddressPool;
+#include "in-addr-util.h"
#include "networkd.h"
struct AddressPool {
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index c0562e5788..1ce1f4d8d6 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -347,9 +347,9 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
link_check_ready(address->link);
if (address->family == AF_INET6 &&
- in_addr_is_link_local(AF_INET6, &address->in_addr) &&
- !address->link->ipv6ll_address) {
- r = link_ipv6ll_gained(address->link);
+ in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
+ in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
+ r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
if (r < 0)
return r;
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 4049a23bdc..accd0a027d 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -28,9 +28,9 @@
typedef struct Address Address;
-#include "networkd.h"
-#include "networkd-network.h"
#include "networkd-link.h"
+#include "networkd-network.h"
+#include "networkd.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index b9c60a3c77..48e3d84055 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -255,6 +255,7 @@ static int dhcp_lease_lost(Link *link) {
}
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
+ link_dirty(link);
link->dhcp4_configured = false;
return 0;
@@ -331,6 +332,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
sd_dhcp_lease_unref(link->dhcp_lease);
link->dhcp4_configured = false;
link->dhcp_lease = sd_dhcp_lease_ref(lease);
+ link_dirty(link);
r = sd_dhcp_lease_get_address(lease, &address);
if (r < 0)
@@ -408,6 +410,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
NULL);
link->dhcp_lease = sd_dhcp_lease_ref(lease);
+ link_dirty(link);
if (link->network->dhcp_mtu) {
uint16_t mtu;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 3ec9b84a93..e67e51f7ef 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -131,7 +131,8 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
case SD_DHCP6_CLIENT_EVENT_STOP:
case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
- log_link_warning(link, "DHCPv6 lease lost");
+ if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
+ log_link_warning(link, "DHCPv6 lease lost");
link->dhcp6_configured = false;
break;
@@ -210,6 +211,9 @@ int dhcp6_configure(Link *link) {
assert(link);
+ if (link->dhcp6_client)
+ return 0;
+
r = sd_dhcp6_client_new(&client);
if (r < 0)
return r;
@@ -220,7 +224,7 @@ int dhcp6_configure(Link *link) {
r = sd_dhcp6_client_set_information_request(client, true);
if (r < 0)
- return r;
+ goto error;
r = sd_dhcp6_client_set_mac(client,
(const uint8_t *) &link->mac,
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index c9222b8cb8..6e5480ee22 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
#include <net/ethernet.h>
+#include <net/if.h>
#include "alloc-util.h"
#include "conf-parser.h"
diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h
index f0efb902d0..c8e3f2ce56 100644
--- a/src/network/networkd-fdb.h
+++ b/src/network/networkd-fdb.h
@@ -23,8 +23,8 @@
typedef struct FdbEntry FdbEntry;
-#include "networkd.h"
#include "networkd-network.h"
+#include "networkd.h"
struct FdbEntry {
Network *network;
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index ed0d861e7a..f4aac4bb93 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -22,8 +22,8 @@
#include <netinet/ether.h>
#include <linux/if.h>
-#include "networkd-link.h"
#include "network-internal.h"
+#include "networkd-link.h"
static int ipv4ll_address_lost(Link *link) {
_cleanup_address_free_ Address *address = NULL;
@@ -201,7 +201,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
}
int ipv4ll_configure(Link *link) {
- uint8_t seed[8];
+ uint64_t seed;
int r;
assert(link);
@@ -215,11 +215,11 @@ int ipv4ll_configure(Link *link) {
}
if (link->udev_device) {
- r = net_get_unique_predictable_data(link->udev_device, seed);
+ r = net_get_unique_predictable_data(link->udev_device, &seed);
if (r >= 0) {
assert_cc(sizeof(unsigned) <= 8);
- r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed);
+ r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed);
if (r < 0)
return r;
}
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 11b35d6cf8..d09a3c2d07 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -19,13 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-util.h"
-#include "strv.h"
-
#include "alloc-util.h"
+#include "bus-util.h"
#include "networkd-link.h"
#include "networkd.h"
#include "parse-util.h"
+#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index c37532bb73..a9d91b07f6 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -506,9 +506,6 @@ static int link_stop_clients(Link *link) {
assert(link->manager);
assert(link->manager->event);
- if (!link->network)
- return 0;
-
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
@@ -618,7 +615,7 @@ void link_check_ready(Link *link) {
return;
if (link_ipv6ll_enabled(link))
- if (!link->ipv6ll_address)
+ if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
return;
if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
@@ -1263,11 +1260,16 @@ static int link_acquire_ipv6_conf(Link *link) {
if (link_dhcp6_enabled(link)) {
assert(link->dhcp6_client);
+ assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
log_link_debug(link, "Acquiring DHCPv6 lease");
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ if (r < 0 && r != -EBUSY)
+ return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
+
r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0)
+ if (r < 0 && r != -EBUSY)
return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
}
@@ -1277,7 +1279,7 @@ static int link_acquire_ipv6_conf(Link *link) {
log_link_debug(link, "Discovering IPv6 routers");
r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
- if (r < 0)
+ if (r < 0 && r != -EBUSY)
return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
}
@@ -2038,9 +2040,13 @@ static int link_configure(Link *link) {
assert(link->network);
assert(link->state == LINK_STATE_PENDING);
- r = link_drop_foreign_config(link);
- if (r < 0)
- return r;
+ /* Drop foreign config, but ignore loopback device.
+ * We do not want to remove loopback address. */
+ if (!(link->flags & IFF_LOOPBACK)) {
+ r = link_drop_foreign_config(link);
+ if (r < 0)
+ return r;
+ }
r = link_set_bridge_fdb(link);
if (r < 0)
@@ -2092,7 +2098,8 @@ static int link_configure(Link *link) {
return r;
}
- if (link_dhcp6_enabled(link)) {
+ if (link_dhcp6_enabled(link) ||
+ link_ipv6_accept_ra_enabled(link)) {
r = dhcp6_configure(link);
if (r < 0)
return r;
@@ -2124,7 +2131,7 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
- if (link->ipv6ll_address) {
+ if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
r = link_acquire_ipv6_conf(link);
if (r < 0)
return r;
@@ -2293,7 +2300,8 @@ network_file_fail:
if (r < 0) {
log_link_debug_errno(link, r, "Failed to extract next address string: %m");
continue;
- } if (r == 0)
+ }
+ if (r == 0)
break;
prefixlen_str = strchr(address_str, '/');
@@ -2323,6 +2331,8 @@ network_file_fail:
}
if (routes) {
+ p = routes;
+
for (;;) {
Route *route;
_cleanup_free_ char *route_str = NULL;
@@ -2337,7 +2347,8 @@ network_file_fail:
if (r < 0) {
log_link_debug_errno(link, r, "Failed to extract next route string: %m");
continue;
- } if (r == 0)
+ }
+ if (r == 0)
break;
prefixlen_str = strchr(route_str, '/');
@@ -2475,17 +2486,17 @@ failed:
return r;
}
-int link_ipv6ll_gained(Link *link) {
+int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
int r;
assert(link);
log_link_info(link, "Gained IPv6LL");
- link->ipv6ll_address = true;
+ link->ipv6ll_address = *address;
link_check_ready(link);
- if (link->network) {
+ if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
r = link_acquire_ipv6_conf(link);
if (r < 0) {
link_enter_failed(link);
@@ -2501,7 +2512,7 @@ static int link_carrier_gained(Link *link) {
assert(link);
- if (link->network) {
+ if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
r = link_acquire_conf(link);
if (r < 0) {
link_enter_failed(link);
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index b564bcbca0..3964a12f37 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -56,9 +56,9 @@ typedef enum LinkOperationalState {
_LINK_OPERSTATE_INVALID = -1
} LinkOperationalState;
-#include "networkd.h"
-#include "networkd-network.h"
#include "networkd-address.h"
+#include "networkd-network.h"
+#include "networkd.h"
struct Link {
Manager *manager;
@@ -69,6 +69,7 @@ struct Link {
char *ifname;
char *state_file;
struct ether_addr mac;
+ struct in6_addr ipv6ll_address;
uint32_t mtu;
struct udev_device *udev_device;
@@ -101,7 +102,6 @@ struct Link {
sd_ipv4ll *ipv4ll;
bool ipv4ll_address:1;
bool ipv4ll_route:1;
- bool ipv6ll_address:1;
bool static_configured;
@@ -144,7 +144,7 @@ int link_save(Link *link);
int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link);
-int link_ipv6ll_gained(Link *link);
+int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
int link_set_mtu(Link *link, uint32_t mtu);
int link_set_hostname(Link *link, const char *hostname);
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 126f9c0fe9..ce9e513ceb 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -75,7 +75,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
address->family = AF_INET6;
address->in_addr.in6 = *prefix;
if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
- memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8);
+ memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
else {
/* see RFC4291 section 2.5.1 */
address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0];
@@ -159,7 +159,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
dhcp6_request_address(link);
r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0 && r != -EALREADY)
+ if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
}
@@ -205,8 +205,12 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
dhcp6_request_address(link);
r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0 && r != -EALREADY)
+ if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
+
+ link->ndisc_configured = true;
+ link_check_ready(link);
+
break;
case SD_NDISC_EVENT_STOP:
break;
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 4e4755f86f..50b9021d09 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -29,8 +29,8 @@
#include "conf-parser.h"
#include "missing.h"
#include "networkd-netdev-bond.h"
-#include "string-util.h"
#include "string-table.h"
+#include "string-util.h"
/*
* Number of seconds between instances where the bonding
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 57c58d83b4..a991bdb5fb 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -22,9 +22,9 @@
#include <net/if.h>
-#include "networkd-netdev-bridge.h"
#include "missing.h"
#include "netlink-util.h"
+#include "networkd-netdev-bridge.h"
/* callback for brige netdev's parameter set */
static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 851e83537e..3d504a8564 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/ioctl.h>
#include <net/if.h>
+#include <sys/ioctl.h>
#include <linux/if_tun.h>
#include "alloc-util.h"
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index bee1a16726..773a1ee6d1 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -23,6 +23,7 @@
#include <linux/veth.h>
#include "sd-netlink.h"
+
#include "networkd-netdev-veth.h"
static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 755ad2f934..7932b93335 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -22,10 +22,11 @@
#include <net/if.h>
#include "sd-netlink.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-link.h"
+
#include "conf-parser.h"
#include "missing.h"
+#include "networkd-link.h"
+#include "networkd-netdev-vxlan.h"
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
VxLan *v;
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index d21f355f5d..16977ea6a9 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -23,9 +23,8 @@
typedef struct VxLan VxLan;
-#include "networkd-netdev.h"
-
#include "in-addr-util.h"
+#include "networkd-netdev.h"
#define VXLAN_VID_MAX (1u << 24) - 1
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index dd0b400c6a..a86a6383da 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -411,7 +411,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
_cleanup_free_ struct ether_addr *mac = NULL;
- uint8_t result[8];
+ uint64_t result;
size_t l, sz;
uint8_t *v;
int r;
@@ -438,10 +438,10 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
/* Let's hash the host machine ID plus the container name. We
* use a fixed, but originally randomly created hash key here. */
- siphash24(result, v, sz, HASH_KEY.bytes);
+ result = siphash24(v, sz, HASH_KEY.bytes);
assert_cc(ETH_ALEN <= sizeof(result));
- memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+ memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
/* see eth_random_addr in the kernel */
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 3b9ab27b67..3ab39efd57 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -26,8 +26,8 @@
typedef struct NetDev NetDev;
typedef struct NetDevVTable NetDevVTable;
-#include "networkd.h"
#include "networkd-link.h"
+#include "networkd.h"
typedef struct netdev_join_callback netdev_join_callback;
@@ -103,16 +103,16 @@ struct NetDev {
LIST_HEAD(netdev_join_callback, callbacks);
};
-#include "networkd-netdev-bridge.h"
#include "networkd-netdev-bond.h"
-#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-macvlan.h"
+#include "networkd-netdev-bridge.h"
+#include "networkd-netdev-dummy.h"
#include "networkd-netdev-ipvlan.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-netdev-veth.h"
+#include "networkd-netdev-macvlan.h"
#include "networkd-netdev-tunnel.h"
-#include "networkd-netdev-dummy.h"
#include "networkd-netdev-tuntap.h"
+#include "networkd-netdev-veth.h"
+#include "networkd-netdev-vlan.h"
+#include "networkd-netdev-vxlan.h"
struct NetDevVTable {
/* How much memory does an object of this unit type need */
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index a27c67eea5..cb3a50d9ba 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -25,12 +25,12 @@
typedef struct Network Network;
-#include "networkd.h"
-#include "networkd-netdev.h"
#include "networkd-address.h"
-#include "networkd-route.h"
#include "networkd-fdb.h"
+#include "networkd-netdev.h"
+#include "networkd-route.h"
#include "networkd-util.h"
+#include "networkd.h"
#define DHCP_ROUTE_METRIC 1024
#define IPV4LL_ROUTE_METRIC 2048
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index b276756674..37c12907d7 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -23,8 +23,8 @@
typedef struct Route Route;
-#include "networkd.h"
#include "networkd-network.h"
+#include "networkd.h"
struct Route {
Network *network;
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 97665fac7a..8086e528bf 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -23,19 +23,19 @@
#include <arpa/inet.h>
+#include "sd-bus.h"
#include "sd-event.h"
#include "sd-netlink.h"
-#include "sd-bus.h"
-#include "udev.h"
#include "hashmap.h"
#include "list.h"
+#include "udev.h"
typedef struct Manager Manager;
-#include "networkd-network.h"
#include "networkd-address-pool.h"
#include "networkd-link.h"
+#include "networkd-network.h"
#include "networkd-util.h"
struct Manager {
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index 438214015d..ecbbe6c3c9 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -1,11 +1,10 @@
-#include "networkd.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-macvlan.h"
#include "dhcp6-internal.h"
#include "dhcp6-protocol.h"
-#include "netlink-internal.h"
#include "ethtool-util.h"
-
+#include "netlink-internal.h"
+#include "networkd-netdev-bond.h"
+#include "networkd-netdev-macvlan.h"
+#include "networkd.h"
#include "test-tables.h"
int main(int argc, char **argv) {
diff --git a/src/network/test-network.c b/src/network/test-network.c
index dbed3795e3..a1a77b6867 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -20,9 +20,9 @@
***/
#include "alloc-util.h"
-#include "networkd.h"
-#include "network-internal.h"
#include "dhcp-lease-internal.h"
+#include "network-internal.h"
+#include "networkd.h"
static void test_deserialize_in_addr(void) {
_cleanup_free_ struct in_addr *addresses = NULL;
diff --git a/src/nspawn/nspawn-cgroup.h b/src/nspawn/nspawn-cgroup.h
index 985fdfaad5..4e8db63750 100644
--- a/src/nspawn/nspawn-cgroup.h
+++ b/src/nspawn/nspawn-cgroup.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdbool.h>
+#include <sys/types.h>
int chown_cgroup(pid_t pid, uid_t uid_shift);
int sync_cgroup(pid_t pid, bool unified_requested);
diff --git a/src/nspawn/nspawn-expose-ports.h b/src/nspawn/nspawn-expose-ports.h
index 39cec28695..cb7340bad7 100644
--- a/src/nspawn/nspawn-expose-ports.h
+++ b/src/nspawn/nspawn-expose-ports.h
@@ -25,8 +25,9 @@
#include "sd-event.h"
#include "sd-netlink.h"
-#include "list.h"
+
#include "in-addr-util.h"
+#include "list.h"
typedef struct ExposePort {
int protocol;
diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c
index c71552879d..8f74c41c71 100644
--- a/src/nspawn/nspawn-network.c
+++ b/src/nspawn/nspawn-network.c
@@ -29,11 +29,11 @@
#include "alloc-util.h"
#include "ether-addr-util.h"
#include "netlink-util.h"
+#include "nspawn-network.h"
#include "siphash24.h"
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
-#include "nspawn-network.h"
#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
@@ -47,7 +47,7 @@ static int generate_mac(
sd_id128_t hash_key,
uint64_t idx) {
- uint8_t result[8];
+ uint64_t result;
size_t l, sz;
uint8_t *v, *i;
int r;
@@ -74,10 +74,10 @@ static int generate_mac(
/* Let's hash the host machine ID plus the container name. We
* use a fixed, but originally randomly created hash key here. */
- siphash24(result, v, sz, hash_key.bytes);
+ result = htole64(siphash24(v, sz, hash_key.bytes));
assert_cc(ETH_ALEN <= sizeof(result));
- memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+ memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
/* see eth_random_addr in the kernel */
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h
index b86effef47..c91fc79c42 100644
--- a/src/nspawn/nspawn-network.h
+++ b/src/nspawn/nspawn-network.h
@@ -22,9 +22,8 @@
***/
#include <net/if.h>
-
-#include <sys/types.h>
#include <stdbool.h>
+#include <sys/types.h>
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c
index 374f958c20..50871464c5 100644
--- a/src/nspawn/nspawn-register.c
+++ b/src/nspawn/nspawn-register.c
@@ -105,6 +105,10 @@ int register_machine(
return bus_log_create_error(r);
}
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", 8192);
+ if (r < 0)
+ return bus_log_create_error(r);
+
r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");
if (r < 0)
return bus_log_create_error(r);
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index dde0d8bd45..10230a5b83 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -24,9 +24,8 @@
#include <stdio.h>
#include "macro.h"
-
-#include "nspawn-mount.h"
#include "nspawn-expose-ports.h"
+#include "nspawn-mount.h"
typedef enum SettingsMask {
SETTING_BOOT = 1 << 0,
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index d2ce731c72..f6a2c0386e 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2283,7 +2283,7 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
pid_t pid;
- pid = PTR_TO_UINT32(userdata);
+ pid = PTR_TO_PID(userdata);
if (pid > 0) {
if (kill(pid, arg_kill_signal) >= 0) {
log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
@@ -3510,8 +3510,8 @@ int main(int argc, char *argv[]) {
if (arg_kill_signal > 0) {
/* Try to kill the init system on SIGINT or SIGTERM */
- sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid));
- sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(pid));
+ sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(pid));
} else {
/* Immediately exit */
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index 969fa9619e..c98a959b3b 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -416,6 +416,9 @@ enum nss_status _nss_mymachines_getpwnam_r(
if (!e || e == p)
goto not_found;
+ if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
+ goto not_found;
+
r = parse_uid(e + 1, &uid);
if (r < 0)
goto not_found;
@@ -573,6 +576,9 @@ enum nss_status _nss_mymachines_getgrnam_r(
if (!e || e == p)
goto not_found;
+ if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
+ goto not_found;
+
r = parse_gid(e + 1, &gid);
if (r < 0)
goto not_found;
diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c
index dc2911e4e8..883d96608d 100644
--- a/src/quotacheck/quotacheck.c
+++ b/src/quotacheck/quotacheck.c
@@ -25,11 +25,11 @@
#include <sys/prctl.h>
#include <unistd.h>
+#include "proc-cmdline.h"
#include "process-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "util.h"
-#include "proc-cmdline.h"
static bool arg_skip = false;
static bool arg_force = false;
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
index 57f99c9ef0..9fc56284d2 100644
--- a/src/remount-fs/remount-fs.c
+++ b/src/remount-fs/remount-fs.c
@@ -19,19 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
+#include <mntent.h>
#include <string.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
-#include <mntent.h>
+#include <unistd.h>
#include "exit-status.h"
#include "log.h"
#include "mount-setup.h"
#include "mount-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "signal-util.h"
+#include "strv.h"
#include "util.h"
/* Goes through /etc/fstab and remounts all API file systems, applying
@@ -39,10 +42,10 @@
* respected */
int main(int argc, char *argv[]) {
- int ret = EXIT_FAILURE;
+ _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_endmntent_ FILE *f = NULL;
struct mntent* me;
- Hashmap *pids = NULL;
+ int r;
if (argc > 1) {
log_error("This program takes no argument.");
@@ -57,21 +60,21 @@ int main(int argc, char *argv[]) {
f = setmntent("/etc/fstab", "r");
if (!f) {
- if (errno == ENOENT)
- return EXIT_SUCCESS;
+ if (errno == ENOENT) {
+ r = 0;
+ goto finish;
+ }
- log_error_errno(errno, "Failed to open /etc/fstab: %m");
- return EXIT_FAILURE;
+ r = log_error_errno(errno, "Failed to open /etc/fstab: %m");
+ goto finish;
}
pids = hashmap_new(NULL);
if (!pids) {
- log_error("Failed to allocate set");
+ r = log_oom();
goto finish;
}
- ret = EXIT_SUCCESS;
-
while ((me = getmntent(f))) {
pid_t pid;
int k;
@@ -87,25 +90,18 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
- ret = EXIT_FAILURE;
- continue;
+ r = log_error_errno(errno, "Failed to fork: %m");
+ goto finish;
}
if (pid == 0) {
- const char *arguments[5];
/* Child */
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
+ (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
- arguments[0] = MOUNT_PATH;
- arguments[1] = me->mnt_dir;
- arguments[2] = "-o";
- arguments[3] = "remount";
- arguments[4] = NULL;
-
- execv(MOUNT_PATH, (char **) arguments);
+ execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));
log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
_exit(EXIT_FAILURE);
@@ -115,20 +111,19 @@ int main(int argc, char *argv[]) {
s = strdup(me->mnt_dir);
if (!s) {
- log_oom();
- ret = EXIT_FAILURE;
- continue;
+ r = log_oom();
+ goto finish;
}
-
- k = hashmap_put(pids, UINT_TO_PTR(pid), s);
+ k = hashmap_put(pids, PID_TO_PTR(pid), s);
if (k < 0) {
- log_error_errno(k, "Failed to add PID to set: %m");
- ret = EXIT_FAILURE;
- continue;
+ free(s);
+ r = log_oom();
+ goto finish;
}
}
+ r = 0;
while (!hashmap_isempty(pids)) {
siginfo_t si = {};
char *s;
@@ -138,12 +133,11 @@ int main(int argc, char *argv[]) {
if (errno == EINTR)
continue;
- log_error_errno(errno, "waitid() failed: %m");
- ret = EXIT_FAILURE;
- break;
+ r = log_error_errno(errno, "waitid() failed: %m");
+ goto finish;
}
- s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
+ s = hashmap_remove(pids, PID_TO_PTR(si.si_pid));
if (s) {
if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
if (si.si_code == CLD_EXITED)
@@ -151,7 +145,7 @@ int main(int argc, char *argv[]) {
else
log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status));
- ret = EXIT_FAILURE;
+ r = -ENOEXEC;
}
free(s);
@@ -159,9 +153,5 @@ int main(int argc, char *argv[]) {
}
finish:
-
- if (pids)
- hashmap_free_free(pids);
-
- return ret;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 432e62dd9f..f68751a2e5 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
#include <getopt.h>
+#include <net/if.h>
#include "sd-bus.h"
@@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "escape.h"
#include "in-addr-util.h"
#include "parse-util.h"
#include "resolved-def.h"
@@ -41,6 +42,7 @@ static int arg_type = 0;
static uint16_t arg_class = 0;
static bool arg_legend = true;
static uint64_t arg_flags = 0;
+static bool arg_resolve_service = false;
static void print_source(uint64_t flags, usec_t rtt) {
char rtt_str[FORMAT_TIMESTAMP_MAX];
@@ -102,10 +104,8 @@ static int resolve_host(sd_bus *bus, const char *name) {
ts = now(CLOCK_MONOTONIC);
r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
- if (r < 0) {
- log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
ts = now(CLOCK_MONOTONIC) - ts;
@@ -114,10 +114,10 @@ static int resolve_host(sd_bus *bus, const char *name) {
return bus_log_parse_error(r);
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
- const void *a;
- size_t sz;
_cleanup_free_ char *pretty = NULL;
int ifindex, family;
+ const void *a;
+ size_t sz;
assert_cc(sizeof(int) == sizeof(int32_t));
@@ -140,7 +140,7 @@ static int resolve_host(sd_bus *bus, const char *name) {
if (sz != FAMILY_ADDRESS_SIZE(family)) {
log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
- continue;
+ return -EINVAL;
}
ifname[0] = 0;
@@ -437,6 +437,207 @@ static int resolve_record(sd_bus *bus, const char *name) {
return 0;
}
+static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
+ const char *canonical_name, *canonical_type, *canonical_domain;
+ _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char ifname[IF_NAMESIZE] = "";
+ size_t indent, sz;
+ uint64_t flags;
+ const char *p;
+ unsigned c;
+ usec_t ts;
+ int r;
+
+ assert(bus);
+ assert(domain);
+
+ if (isempty(name))
+ name = NULL;
+ if (isempty(type))
+ type = NULL;
+
+ if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
+ return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
+
+ if (name)
+ log_debug("Resolving service \"%s\" of type %s in %s (family %s, interface %s).", name, type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
+ else if (type)
+ log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
+ else
+ log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &req,
+ "org.freedesktop.resolve1",
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ "ResolveService");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ ts = now(CLOCK_MONOTONIC);
+
+ r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
+ if (r < 0)
+ return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
+
+ ts = now(CLOCK_MONOTONIC) - ts;
+
+ r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ indent =
+ (name ? strlen(name) + 1 : 0) +
+ (type ? strlen(type) + 1 : 0) +
+ strlen(domain) + 2;
+
+ c = 0;
+ while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
+ uint16_t priority, weight, port;
+ const char *hostname, *canonical;
+
+ r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (name)
+ printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
+ if (type)
+ printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
+
+ printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
+ (int) strlen(domain), c == 0 ? domain : "",
+ c == 0 ? ":" : " ",
+ hostname, port,
+ priority, weight);
+
+ r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
+ _cleanup_free_ char *pretty = NULL;
+ int ifindex, family;
+ const void *a;
+
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
+ r = sd_bus_message_read(reply, "ii", &ifindex, &family);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_read_array(reply, 'y', &a, &sz);
+ 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);
+
+ if (!IN_SET(family, AF_INET, AF_INET6)) {
+ log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
+ continue;
+ }
+
+ if (sz != FAMILY_ADDRESS_SIZE(family)) {
+ log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
+ return -EINVAL;
+ }
+
+ ifname[0] = 0;
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+
+ r = in_addr_to_string(family, a, &pretty);
+ if (r < 0)
+ return log_error_errno(r, "Failed to print address for %s: %m", name);
+
+ printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
+ }
+ 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);
+
+ r = sd_bus_message_read(reply, "s", &canonical);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (!streq(hostname, canonical))
+ printf("%*s(%s)\n", (int) indent, "", canonical);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ 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);
+
+ r = sd_bus_message_enter_container(reply, 'a', "ay");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ c = 0;
+ while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
+ _cleanup_free_ char *escaped = NULL;
+
+ escaped = cescape_length(p, sz);
+ if (!escaped)
+ return log_oom();
+
+ printf("%*s%s\n", (int) indent, "", escaped);
+ 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);
+
+ r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (isempty(canonical_name))
+ canonical_name = NULL;
+ if (isempty(canonical_type))
+ canonical_type = NULL;
+
+ if (!streq_ptr(name, canonical_name) ||
+ !streq_ptr(type, canonical_type) ||
+ !streq_ptr(domain, canonical_domain)) {
+
+ printf("%*s(", (int) indent, "");
+
+ if (canonical_name)
+ printf("%s/", canonical_name);
+ if (canonical_type)
+ printf("%s/", canonical_type);
+
+ printf("%s)\n", canonical_domain);
+ }
+
+ print_source(flags, ts);
+
+ return 0;
+}
+
static void help_dns_types(void) {
int i;
const char *t;
@@ -464,33 +665,49 @@ static void help_dns_classes(void) {
}
static void help(void) {
- printf("%s [OPTIONS...]\n\n"
- "Resolve IPv4 or IPv6 addresses.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -4 Resolve IPv4 addresses\n"
- " -6 Resolve IPv6 addresses\n"
- " -i INTERFACE Look on interface\n"
- " -p --protocol=PROTOCOL Look via protocol\n"
- " -t --type=TYPE Query RR with DNS type\n"
- " -c --class=CLASS Query RR with DNS class\n"
- " --legend[=BOOL] Do [not] print column headers\n"
- , program_invocation_short_name);
+ printf("%s [OPTIONS...] NAME...\n"
+ "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
+ "Resolve domain names, IPv4 or IPv6 addresses, resource records, and services.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " -4 Resolve IPv4 addresses\n"
+ " -6 Resolve IPv6 addresses\n"
+ " -i INTERFACE Look on interface\n"
+ " -p --protocol=PROTOCOL Look via protocol\n"
+ " -t --type=TYPE Query RR with DNS type\n"
+ " -c --class=CLASS Query RR with DNS class\n"
+ " --service Resolve service (SRV)\n"
+ " --service-address=BOOL Do [not] resolve address for services\n"
+ " --service-txt=BOOL Do [not] resolve TXT records for services\n"
+ " --cname=BOOL Do [not] follow CNAME redirects\n"
+ " --search=BOOL Do [not] use search domains\n"
+ " --legend=BOOL Do [not] print column headers\n"
+ , program_invocation_short_name, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_LEGEND,
+ ARG_SERVICE,
+ ARG_CNAME,
+ ARG_SERVICE_ADDRESS,
+ ARG_SERVICE_TXT,
+ ARG_SEARCH,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "type", required_argument, NULL, 't' },
- { "class", required_argument, NULL, 'c' },
- { "legend", optional_argument, NULL, ARG_LEGEND },
- { "protocol", required_argument, NULL, 'p' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "type", required_argument, NULL, 't' },
+ { "class", required_argument, NULL, 'c' },
+ { "legend", required_argument, NULL, ARG_LEGEND },
+ { "protocol", required_argument, NULL, 'p' },
+ { "cname", required_argument, NULL, ARG_CNAME },
+ { "service", no_argument, NULL, ARG_SERVICE },
+ { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
+ { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
+ { "search", required_argument, NULL, ARG_SEARCH },
{}
};
@@ -563,16 +780,11 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_LEGEND:
- if (optarg) {
- r = parse_boolean(optarg);
- if (r < 0) {
- log_error("Failed to parse --legend= argument");
- return r;
- }
-
- arg_legend = !!r;
- } else
- arg_legend = false;
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --legend= argument");
+
+ arg_legend = r;
break;
case 'p':
@@ -591,6 +803,50 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_SERVICE:
+ arg_resolve_service = true;
+ break;
+
+ case ARG_CNAME:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --cname= argument.");
+ if (r == 0)
+ arg_flags |= SD_RESOLVED_NO_CNAME;
+ else
+ arg_flags &= ~SD_RESOLVED_NO_CNAME;
+ break;
+
+ case ARG_SERVICE_ADDRESS:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --service-address= argument.");
+ if (r == 0)
+ arg_flags |= SD_RESOLVED_NO_ADDRESS;
+ else
+ arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
+ break;
+
+ case ARG_SERVICE_TXT:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --service-txt= argument.");
+ if (r == 0)
+ arg_flags |= SD_RESOLVED_NO_TXT;
+ else
+ arg_flags &= ~SD_RESOLVED_NO_TXT;
+ break;
+
+ case ARG_SEARCH:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --search argument.");
+ if (r == 0)
+ arg_flags |= SD_RESOLVED_NO_SEARCH;
+ else
+ arg_flags &= ~SD_RESOLVED_NO_SEARCH;
+ break;
+
case '?':
return -EINVAL;
@@ -599,7 +855,12 @@ static int parse_argv(int argc, char *argv[]) {
}
if (arg_type == 0 && arg_class != 0) {
- log_error("--class= may only be used in conjunction with --type=");
+ log_error("--class= may only be used in conjunction with --type=.");
+ return -EINVAL;
+ }
+
+ if (arg_type != 0 && arg_resolve_service) {
+ log_error("--service and --type= may not be combined.");
return -EINVAL;
}
@@ -632,6 +893,28 @@ int main(int argc, char **argv) {
goto finish;
}
+ if (arg_resolve_service) {
+
+ if (argc < optind + 1) {
+ log_error("Domain specification required.");
+ r = -EINVAL;
+ goto finish;
+
+ } else if (argc == optind + 1)
+ r = resolve_service(bus, NULL, NULL, argv[optind]);
+ else if (argc == optind + 2)
+ r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
+ else if (argc == optind + 3)
+ r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
+ else {
+ log_error("Too many arguments");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ goto finish;
+ }
+
while (argv[optind]) {
int family, ifindex, k;
union in_addr_union a;
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index f0a3b607d4..62bb08a2e8 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -31,15 +31,14 @@ static int reply_query_state(DnsQuery *q) {
const char *name;
int r;
- if (q->request_hostname)
- name = q->request_hostname;
- else {
+ if (q->request_address_valid) {
r = in_addr_to_string(q->request_family, &q->request_address, &ip);
if (r < 0)
return r;
name = ip;
- }
+ } else
+ name = dns_question_first_name(q->question);
switch (q->state) {
@@ -132,10 +131,9 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin
}
static void bus_method_resolve_hostname_complete(DnsQuery *q) {
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- unsigned added = 0, i;
+ unsigned added = 0;
int r;
assert(q);
@@ -145,6 +143,16 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
goto finish;
}
+ r = dns_query_process_cname(q);
+ if (r == -ELOOP) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
+ goto finish;
+ }
+ if (r < 0)
+ goto finish;
+ if (r > 0) /* This was a cname, and the query was restarted. */
+ return;
+
r = sd_bus_message_new_method_return(q->request, &reply);
if (r < 0)
goto finish;
@@ -154,92 +162,42 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
goto finish;
if (q->answer) {
- answer = dns_answer_ref(q->answer);
+ DnsResourceRecord *rr;
+ int ifindex;
- for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->items[i].rr);
+ DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
if (r < 0)
goto finish;
- if (r == 0) {
- /* Hmm, if this is not an address record,
- maybe it's a cname? If so, remember this */
- r = dns_question_matches_cname(q->question, answer->items[i].rr);
- if (r < 0)
- goto finish;
- if (r > 0)
- cname = dns_resource_record_ref(answer->items[i].rr);
-
+ if (r == 0)
continue;
- }
- r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
+ r = append_address(reply, rr, ifindex);
if (r < 0)
goto finish;
if (!canonical)
- canonical = dns_resource_record_ref(answer->items[i].rr);
+ canonical = dns_resource_record_ref(rr);
added ++;
}
}
- if (added == 0) {
- if (!cname) {
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of requested type", q->request_hostname);
- goto finish;
- }
-
- /* This has a cname? Then update the query with the
- * new cname. */
- r = dns_query_cname_redirect(q, cname);
- if (r < 0) {
- if (r == -ELOOP)
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
- else
- r = sd_bus_reply_method_errno(q->request, -r, NULL);
-
- goto finish;
- }
-
- /* Before we restart the query, let's see if any of
- * the RRs we already got already answers our query */
- for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->items[i].rr);
- if (r < 0)
- goto finish;
- if (r == 0)
- continue;
-
- r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
- if (r < 0)
- goto finish;
-
- if (!canonical)
- canonical = dns_resource_record_ref(answer->items[i].rr);
-
- added++;
- }
-
- /* If we didn't find anything, then let's restart the
- * query, this time with the cname */
- if (added <= 0) {
- r = dns_query_go(q);
- if (r < 0) {
- r = sd_bus_reply_method_errno(q->request, -r, NULL);
- goto finish;
- }
-
- return;
- }
+ if (added <= 0) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
+ goto finish;
}
r = sd_bus_message_close_container(reply);
if (r < 0)
goto finish;
- /* Return the precise spelling and uppercasing reported by the server */
+ /* Return the precise spelling and uppercasing and CNAME target reported by the server */
assert(canonical);
- r = sd_bus_message_append(reply, "st", DNS_RESOURCE_KEY_NAME(canonical->key), SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
+ r = sd_bus_message_append(
+ reply, "st",
+ DNS_RESOURCE_KEY_NAME(canonical->key),
+ SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
if (r < 0)
goto finish;
@@ -248,23 +206,23 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
finish:
if (r < 0) {
log_error_errno(r, "Failed to send hostname reply: %m");
- sd_bus_reply_method_errno(q->request, -r, NULL);
+ sd_bus_reply_method_errno(q->request, r, NULL);
}
dns_query_free(q);
}
-static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error) {
+static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
assert(flags);
if (ifindex < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
- if (*flags & ~SD_RESOLVED_FLAGS_ALL)
+ 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 == 0)
- *flags = SD_RESOLVED_FLAGS_DEFAULT;
+ if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
+ *flags |= SD_RESOLVED_PROTOCOLS_ALL;
return 0;
}
@@ -281,6 +239,8 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
assert(message);
assert(m);
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
if (r < 0)
return r;
@@ -288,41 +248,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
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 = dns_name_normalize(hostname, NULL);
+ r = dns_name_is_valid(hostname);
if (r < 0)
+ return r;
+ if (r == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
- r = check_ifindex_flags(ifindex, &flags, error);
+ r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
if (r < 0)
return r;
- question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
- if (!question)
- return -ENOMEM;
-
- if (family != AF_INET6) {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
-
- key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
- if (!key)
- return -ENOMEM;
-
- r = dns_question_add(question, key);
- if (r < 0)
- return r;
- }
-
- if (family != AF_INET) {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
-
- key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
- if (!key)
- return -ENOMEM;
-
- r = dns_question_add(question, key);
- if (r < 0)
- return r;
- }
+ r = dns_question_new_address(&question, family, hostname);
+ if (r < 0)
+ return r;
r = dns_query_new(m, &q, question, ifindex, flags);
if (r < 0)
@@ -330,27 +268,28 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
q->request = sd_bus_message_ref(message);
q->request_family = family;
- q->request_hostname = hostname;
q->complete = bus_method_resolve_hostname_complete;
r = dns_query_bus_track(q, message);
if (r < 0)
- return r;
+ goto fail;
r = dns_query_go(q);
- if (r < 0) {
- dns_query_free(q);
- return r;
- }
+ if (r < 0)
+ goto fail;
return 1;
+
+fail:
+ dns_query_free(q);
+ return r;
}
static void bus_method_resolve_address_complete(DnsQuery *q) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- unsigned added = 0, i;
- int r;
+ DnsResourceRecord *rr;
+ unsigned added = 0;
+ int ifindex, r;
assert(q);
@@ -359,6 +298,16 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
goto finish;
}
+ r = dns_query_process_cname(q);
+ if (r == -ELOOP) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
+ goto finish;
+ }
+ if (r < 0)
+ goto finish;
+ if (r > 0) /* This was a cname, and the query was restarted. */
+ return;
+
r = sd_bus_message_new_method_return(q->request, &reply);
if (r < 0)
goto finish;
@@ -368,16 +317,14 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
goto finish;
if (q->answer) {
- answer = dns_answer_ref(q->answer);
-
- for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->items[i].rr);
+ DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = sd_bus_message_append(reply, "(is)", answer->items[i].ifindex, answer->items[i].rr->ptr.name);
+ r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
if (r < 0)
goto finish;
@@ -385,12 +332,11 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
}
}
- if (added == 0) {
+ if (added <= 0) {
_cleanup_free_ char *ip = NULL;
in_addr_to_string(q->request_family, &q->request_address, &ip);
-
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
goto finish;
}
@@ -407,16 +353,14 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
finish:
if (r < 0) {
log_error_errno(r, "Failed to send address reply: %m");
- sd_bus_reply_method_errno(q->request, -r, NULL);
+ sd_bus_reply_method_errno(q->request, r, NULL);
}
dns_query_free(q);
}
static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
- _cleanup_free_ char *reverse = NULL;
Manager *m = userdata;
int family, ifindex;
uint64_t flags;
@@ -428,6 +372,8 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
assert(message);
assert(m);
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
r = sd_bus_message_read(message, "ii", &ifindex, &family);
if (r < 0)
return r;
@@ -446,54 +392,77 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- r = check_ifindex_flags(ifindex, &flags, error);
+ r = check_ifindex_flags(ifindex, &flags, 0, error);
if (r < 0)
return r;
- r = dns_name_reverse(family, d, &reverse);
+ r = dns_question_new_reverse(&question, family, d);
if (r < 0)
return r;
- question = dns_question_new(1);
- if (!question)
- return -ENOMEM;
+ r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
+ if (r < 0)
+ return r;
- key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
- if (!key)
- return -ENOMEM;
+ q->request = sd_bus_message_ref(message);
+ q->request_family = family;
+ memcpy(&q->request_address, d, sz);
+ q->complete = bus_method_resolve_address_complete;
+
+ r = dns_query_bus_track(q, message);
+ if (r < 0)
+ goto fail;
- reverse = NULL;
+ r = dns_query_go(q);
+ if (r < 0)
+ goto fail;
- r = dns_question_add(question, key);
+ return 1;
+
+fail:
+ dns_query_free(q);
+ return r;
+}
+
+static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+ size_t start;
+ int r;
+
+ assert(m);
+ assert(rr);
+
+ r = sd_bus_message_open_container(m, 'r', "iqqay");
if (r < 0)
return r;
- r = dns_query_new(m, &q, question, ifindex, flags);
+ r = sd_bus_message_append(m, "iqq",
+ ifindex,
+ rr->key->class,
+ rr->key->type);
if (r < 0)
return r;
- q->request = sd_bus_message_ref(message);
- q->request_family = family;
- memcpy(&q->request_address, d, sz);
- q->complete = bus_method_resolve_address_complete;
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+ if (r < 0)
+ return r;
- r = dns_query_bus_track(q, message);
+ p->refuse_compression = true;
+
+ r = dns_packet_append_rr(p, rr, &start);
if (r < 0)
return r;
- r = dns_query_go(q);
- if (r < 0) {
- dns_query_free(q);
+ r = sd_bus_message_append_array(m, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
+ if (r < 0)
return r;
- }
- return 1;
+ return sd_bus_message_close_container(m);
}
static void bus_method_resolve_record_complete(DnsQuery *q) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- unsigned added = 0, i;
+ unsigned added = 0;
int r;
assert(q);
@@ -503,6 +472,16 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
goto finish;
}
+ r = dns_query_process_cname(q);
+ if (r == -ELOOP) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
+ goto finish;
+ }
+ if (r < 0)
+ goto finish;
+ if (r > 0) /* Following a CNAME */
+ return;
+
r = sd_bus_message_new_method_return(q->request, &reply);
if (r < 0)
goto finish;
@@ -512,44 +491,17 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
goto finish;
if (q->answer) {
- answer = dns_answer_ref(q->answer);
-
- for (i = 0; i < answer->n_rrs; i++) {
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- size_t start;
+ DnsResourceRecord *rr;
+ int ifindex;
- r = dns_question_matches_rr(q->question, answer->items[i].rr);
+ DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
- if (r < 0)
- goto finish;
-
- p->refuse_compression = true;
-
- r = dns_packet_append_rr(p, answer->items[i].rr, &start);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_open_container(reply, 'r', "iqqay");
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_append(reply, "iqq",
- answer->items[i].ifindex,
- answer->items[i].rr->key->class,
- answer->items[i].rr->key->type);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_close_container(reply);
+ r = bus_message_append_rr(reply, rr, ifindex);
if (r < 0)
goto finish;
@@ -558,7 +510,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
}
if (added <= 0) {
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", q->request_hostname);
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_question_first_name(q->question));
goto finish;
}
@@ -575,7 +527,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
finish:
if (r < 0) {
log_error_errno(r, "Failed to send record reply: %m");
- sd_bus_reply_method_errno(q->request, -r, NULL);
+ sd_bus_reply_method_errno(q->request, r, NULL);
}
dns_query_free(q);
@@ -594,15 +546,19 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
assert(message);
assert(m);
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
if (r < 0)
return r;
- r = dns_name_normalize(name, NULL);
+ r = dns_name_is_valid(name);
if (r < 0)
+ return r;
+ if (r == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
- r = check_ifindex_flags(ifindex, &flags, error);
+ r = check_ifindex_flags(ifindex, &flags, 0, error);
if (r < 0)
return r;
@@ -618,32 +574,657 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
- r = dns_query_new(m, &q, question, ifindex, flags);
+ r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;
q->request = sd_bus_message_ref(message);
- q->request_hostname = name;
q->complete = bus_method_resolve_record_complete;
r = dns_query_bus_track(q, message);
if (r < 0)
- return r;
+ goto fail;
r = dns_query_go(q);
+ if (r < 0)
+ goto fail;
+
+ return 1;
+
+fail:
+ dns_query_free(q);
+ return r;
+}
+
+static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
+ DnsQuery *aux;
+ int r;
+
+ assert(q);
+ assert(reply);
+ assert(rr);
+ assert(rr->key);
+
+ if (rr->key->type != DNS_TYPE_SRV)
+ return 0;
+
+ if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
+ /* First, let's see if we could find an appropriate A or AAAA
+ * record for the SRV record */
+ LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
+ DnsResourceRecord *zz;
+
+ if (aux->state != DNS_TRANSACTION_SUCCESS)
+ continue;
+ if (aux->auxiliary_result != 0)
+ continue;
+
+ r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ DNS_ANSWER_FOREACH(zz, aux->answer) {
+
+ r = dns_question_matches_rr(aux->question, zz, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ canonical = dns_resource_record_ref(zz);
+ break;
+ }
+
+ if (canonical)
+ break;
+ }
+
+ /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
+ if (!canonical)
+ return 0;
+ }
+
+ r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(
+ reply,
+ "qqqs",
+ rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+ if (r < 0)
+ return r;
+
+ if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
+ LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
+ DnsResourceRecord *zz;
+ int ifindex;
+
+ if (aux->state != DNS_TRANSACTION_SUCCESS)
+ continue;
+ if (aux->auxiliary_result != 0)
+ continue;
+
+ r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
+
+ r = dns_question_matches_rr(aux->question, zz, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ r = append_address(reply, zz, ifindex);
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ /* Note that above we appended the hostname as encoded in the
+ * SRV, and here the canonical hostname this maps to. */
+ r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
+ DnsTxtItem *i;
+ int r;
+
+ assert(reply);
+ assert(rr);
+ assert(rr->key);
+
+ if (rr->key->type != DNS_TYPE_TXT)
+ return 0;
+
+ LIST_FOREACH(items, i, rr->txt.items) {
+
+ if (i->length <= 0)
+ continue;
+
+ r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+}
+
+static void resolve_service_all_complete(DnsQuery *q) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
+ DnsQuery *aux;
+ unsigned added = false;
+ int r;
+
+ assert(q);
+
+ if (q->block_all_complete > 0)
+ return;
+
+ if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
+ DnsQuery *bad = NULL;
+ bool have_success = false;
+
+ LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
+
+ switch (aux->state) {
+
+ case DNS_TRANSACTION_PENDING:
+ /* If an auxiliary query is still pending, let's wait */
+ return;
+
+ case DNS_TRANSACTION_SUCCESS:
+ if (aux->auxiliary_result == 0)
+ have_success = true;
+ else
+ bad = aux;
+ break;
+
+ default:
+ bad = aux;
+ break;
+ }
+ }
+
+ if (!have_success) {
+ /* We can only return one error, hence pick the last error we encountered */
+
+ assert(bad);
+
+ if (bad->state == DNS_TRANSACTION_SUCCESS) {
+ assert(bad->auxiliary_result != 0);
+
+ if (bad->auxiliary_result == -ELOOP) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(bad->question));
+ goto finish;
+ }
+
+ r = bad->auxiliary_result;
+ goto finish;
+ }
+
+ r = reply_query_state(bad);
+ goto finish;
+ }
+ }
+
+ r = sd_bus_message_new_method_return(q->request, &reply);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
+ if (r < 0)
+ goto finish;
+
+ if (q->answer) {
+ DnsResourceRecord *rr;
+
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
+ if (r < 0)
+ goto finish;
+ if (r == 0)
+ continue;
+
+ r = append_srv(q, reply, rr);
+ if (r < 0)
+ goto finish;
+ if (r == 0) /* not an SRV record */
+ continue;
+
+ if (!canonical)
+ canonical = dns_resource_record_ref(rr);
+
+ added++;
+ }
+ }
+
+ if (added <= 0) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
+ goto finish;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(reply, 'a', "ay");
+ if (r < 0)
+ goto finish;
+
+ if (q->answer) {
+ DnsResourceRecord *rr;
+
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
+ if (r < 0)
+ goto finish;
+ if (r == 0)
+ continue;
+
+ r = append_txt(reply, rr);
+ if (r < 0)
+ goto finish;
+ }
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ goto finish;
+
+ assert(canonical);
+ r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_append(
+ reply,
+ "ssst",
+ name, type, domain,
+ SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_send(q->manager->bus, reply, NULL);
+
+finish:
if (r < 0) {
- dns_query_free(q);
+ log_error_errno(r, "Failed to send service reply: %m");
+ sd_bus_reply_method_errno(q->request, r, NULL);
+ }
+
+ dns_query_free(q);
+}
+
+static void resolve_service_hostname_complete(DnsQuery *q) {
+ int r;
+
+ assert(q);
+ assert(q->auxiliary_for);
+
+ if (q->state != DNS_TRANSACTION_SUCCESS) {
+ resolve_service_all_complete(q->auxiliary_for);
+ return;
+ }
+
+ r = dns_query_process_cname(q);
+ if (r > 0) /* This was a cname, and the query was restarted. */
+ return;
+
+ /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
+ q->auxiliary_result = r;
+ resolve_service_all_complete(q->auxiliary_for);
+}
+
+static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
+ _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
+ DnsQuery *aux;
+ int r;
+
+ assert(q);
+ assert(rr);
+ assert(rr->key);
+ assert(rr->key->type == DNS_TYPE_SRV);
+
+ /* OK, we found an SRV record for the service. Let's resolve
+ * the hostname included in it */
+
+ r = dns_question_new_address(&question, q->request_family, rr->srv.name);
+ if (r < 0)
+ return r;
+
+ r = dns_query_new(q->manager, &aux, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
+ if (r < 0)
return r;
+
+ aux->request_family = q->request_family;
+ aux->complete = resolve_service_hostname_complete;
+
+ r = dns_query_make_auxiliary(aux, q);
+ if (r == -EAGAIN) {
+ /* Too many auxiliary lookups? If so, don't complain,
+ * let's just not add this one, we already have more
+ * than enough */
+
+ dns_query_free(aux);
+ return 0;
}
+ if (r < 0)
+ goto fail;
+
+ /* Note that auxiliary queries do not track the original bus
+ * client, only the primary request does that. */
+
+ r = dns_query_go(aux);
+ if (r < 0)
+ goto fail;
return 1;
+
+fail:
+ dns_query_free(aux);
+ return r;
+}
+
+static void bus_method_resolve_service_complete(DnsQuery *q) {
+ unsigned found = 0;
+ int r;
+
+ assert(q);
+
+ if (q->state != DNS_TRANSACTION_SUCCESS) {
+ r = reply_query_state(q);
+ goto finish;
+ }
+
+ r = dns_query_process_cname(q);
+ if (r == -ELOOP) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
+ goto finish;
+ }
+ if (r < 0)
+ goto finish;
+ if (r > 0) /* This was a cname, and the query was restarted. */
+ return;
+
+ if (q->answer) {
+ DnsResourceRecord *rr;
+ int ifindex;
+
+ DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
+ if (r < 0)
+ goto finish;
+ if (r == 0)
+ continue;
+
+ if (rr->key->type != DNS_TYPE_SRV)
+ continue;
+
+ if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
+ q->block_all_complete ++;
+ r = resolve_service_hostname(q, rr, ifindex);
+ q->block_all_complete --;
+
+ if (r < 0)
+ goto finish;
+ }
+
+ found++;
+ }
+ }
+
+ if (found <= 0) {
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
+ goto finish;
+ }
+
+ /* Maybe we are already finished? check now... */
+ resolve_service_all_complete(q);
+ return;
+
+finish:
+ if (r < 0) {
+ log_error_errno(r, "Failed to send service reply: %m");
+ sd_bus_reply_method_errno(q->request, r, NULL);
+ }
+
+ dns_query_free(q);
+}
+
+static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
+ const char *name, *type, *domain, *joined;
+ _cleanup_free_ char *n = NULL;
+ Manager *m = userdata;
+ int family, ifindex;
+ uint64_t flags;
+ DnsQuery *q;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
+ r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
+ if (r < 0)
+ return r;
+
+ 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);
+
+ if (isempty(name))
+ name = NULL;
+ else {
+ if (!dns_service_name_is_valid(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
+ }
+
+ if (isempty(type))
+ type = NULL;
+ else if (!dns_srv_type_is_valid(type))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
+
+ r = dns_name_is_valid(domain);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
+
+ if (name && !type)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
+
+ r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
+ if (r < 0)
+ return r;
+
+ if (type) {
+ /* If the type is specified, we generate the full domain name to look up ourselves */
+ r = dns_service_join(name, type, domain, &n);
+ if (r < 0)
+ return r;
+
+ joined = n;
+ } else
+ /* If no type is specified, we assume the domain
+ * contains the full domain name to lookup already */
+ joined = domain;
+
+ r = dns_question_new_service(&question, joined, !(flags & SD_RESOLVED_NO_TXT));
+ if (r < 0)
+ return r;
+
+ r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
+ if (r < 0)
+ return r;
+
+ q->request = sd_bus_message_ref(message);
+ q->request_family = family;
+ q->complete = bus_method_resolve_service_complete;
+
+ r = dns_query_bus_track(q, message);
+ if (r < 0)
+ goto fail;
+
+ r = dns_query_go(q);
+ if (r < 0)
+ goto fail;
+
+ return 1;
+
+fail:
+ dns_query_free(q);
+ return r;
+}
+
+static int append_dns_server(sd_bus_message *reply, DnsServer *s) {
+ int r;
+
+ assert(reply);
+ assert(s);
+
+ r = sd_bus_message_open_container(reply, 'r', "iiay");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "ii", s->link ? s->link->ifindex : 0, s->family);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_close_container(reply);
+}
+
+static int bus_property_get_dns_servers(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ unsigned c = 0;
+ DnsServer *s;
+ Iterator i;
+ Link *l;
+ int r;
+
+ assert(reply);
+ assert(m);
+
+ r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(servers, s, m->dns_servers) {
+ r = append_dns_server(reply, s);
+ if (r < 0)
+ return r;
+
+ c++;
+ }
+
+ HASHMAP_FOREACH(l, m->links, i) {
+ LIST_FOREACH(servers, s, l->dns_servers) {
+ r = append_dns_server(reply, s);
+ if (r < 0)
+ return r;
+ c++;
+ }
+ }
+
+ if (c == 0) {
+ LIST_FOREACH(servers, s, m->fallback_dns_servers) {
+ r = append_dns_server(reply, s);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
+static int bus_property_get_search_domains(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ DnsSearchDomain *d;
+ Iterator i;
+ Link *l;
+ int r;
+
+ assert(reply);
+ assert(m);
+
+ r = sd_bus_message_open_container(reply, 'a', "(is)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(domains, d, m->search_domains) {
+ r = sd_bus_message_append(reply, "(is)", 0, d->name);
+ if (r < 0)
+ return r;
+ }
+
+ HASHMAP_FOREACH(l, m->links, i) {
+ LIST_FOREACH(domains, d, l->search_domains) {
+ r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return sd_bus_message_close_container(reply);
}
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
+ SD_BUS_PROPERTY("DNSServers", "a(iiay)", bus_property_get_dns_servers, 0, 0),
+ SD_BUS_PROPERTY("SearchDomains", "a(is)", bus_property_get_search_domains, 0, 0),
+
SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 9207719551..3fc7d9ae3d 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -27,53 +27,99 @@
#include "resolved-conf.h"
#include "string-util.h"
-int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) {
- DnsServer *first;
+int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
+ union in_addr_union address;
+ int family, r;
+ DnsServer *s;
+
+ assert(m);
+ assert(word);
+
+ r = in_addr_from_string_auto(word, &family, &address);
+ if (r < 0)
+ return r;
+
+ /* Filter out duplicates */
+ s = dns_server_find(manager_get_first_dns_server(m, type), family, &address);
+ if (s) {
+ /*
+ * Drop the marker. This is used to find the servers
+ * that ceased to exist, see
+ * manager_mark_dns_servers() and
+ * manager_flush_marked_dns_servers().
+ */
+ dns_server_move_back_and_unmark(s);
+ return 0;
+ }
+
+ return dns_server_new(m, NULL, type, NULL, family, &address);
+}
+
+int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
int r;
assert(m);
assert(string);
- first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers;
-
for(;;) {
_cleanup_free_ char *word = NULL;
- union in_addr_union addr;
- bool found = false;
- DnsServer *s;
- int family;
r = extract_first_word(&string, &word, NULL, 0);
if (r < 0)
- return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string);
+ return r;
if (r == 0)
break;
- r = in_addr_from_string_auto(word, &family, &addr);
- if (r < 0) {
- log_warning("Ignoring invalid DNS address '%s'", word);
- continue;
- }
+ r = manager_add_dns_server_by_string(m, type, word);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add DNS server address '%s', ignoring.", word);
+ }
+
+ return 0;
+}
- /* Filter out duplicates */
- LIST_FOREACH(servers, s, first)
- if (s->family == family && in_addr_equal(family, &s->address, &addr)) {
- found = true;
- break;
- }
+int manager_add_search_domain_by_string(Manager *m, const char *domain) {
+ DnsSearchDomain *d;
+ int r;
- if (found)
- continue;
+ assert(m);
+ assert(domain);
- r = dns_server_new(m, NULL, type, NULL, family, &addr);
+ r = dns_search_domain_find(m->search_domains, domain, &d);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ dns_search_domain_move_back_and_unmark(d);
+ return 0;
+ }
+
+ return dns_search_domain_new(m, NULL, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
+}
+
+int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
+ int r;
+
+ assert(m);
+ assert(string);
+
+ for(;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES);
if (r < 0)
return r;
+ if (r == 0)
+ break;
+
+ r = manager_add_search_domain_by_string(m, word);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add search domain '%s', ignoring.", word);
}
return 0;
}
-int config_parse_dnsv(
+int config_parse_dns_servers(
const char *unit,
const char *filename,
unsigned line,
@@ -95,10 +141,10 @@ int config_parse_dnsv(
if (isempty(rvalue))
/* Empty assignment means clear the list */
- manager_flush_dns_servers(m, ltype);
+ dns_server_unlink_all(manager_get_first_dns_server(m, ltype));
else {
/* Otherwise, add to the list */
- r = manager_parse_dns_server(m, ltype, rvalue);
+ r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
return 0;
@@ -109,6 +155,47 @@ int config_parse_dnsv(
* /etc/resolv.conf */
if (ltype == DNS_SERVER_SYSTEM)
m->read_resolv_conf = false;
+ if (ltype == DNS_SERVER_FALLBACK)
+ m->need_builtin_fallbacks = false;
+
+ return 0;
+}
+
+int config_parse_search_domains(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Manager *m = userdata;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(m);
+
+ if (isempty(rvalue))
+ /* Empty assignment means clear the list */
+ dns_search_domain_unlink_all(m->search_domains);
+ else {
+ /* Otherwise, add to the list */
+ r = manager_parse_search_domains_and_warn(m, rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse search domains string '%s'. Ignoring.", rvalue);
+ return 0;
+ }
+ }
+
+ /* If we have a manual setting, then we stop reading
+ * /etc/resolv.conf */
+ m->read_resolv_conf = false;
return 0;
}
@@ -148,11 +235,24 @@ int config_parse_support(
}
int manager_parse_config_file(Manager *m) {
+ int r;
+
assert(m);
- return config_parse_many(PKGSYSCONFDIR "/resolved.conf",
- CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
- "Resolve\0",
- config_item_perf_lookup, resolved_gperf_lookup,
- false, m);
+ r = config_parse_many(PKGSYSCONFDIR "/resolved.conf",
+ CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
+ "Resolve\0",
+ config_item_perf_lookup, resolved_gperf_lookup,
+ false, m);
+ if (r < 0)
+ return r;
+
+ if (m->need_builtin_fallbacks) {
+ r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+
}
diff --git a/src/resolve/resolved-conf.h b/src/resolve/resolved-conf.h
index b3dbea7b6b..28d2549d35 100644
--- a/src/resolve/resolved-conf.h
+++ b/src/resolve/resolved-conf.h
@@ -23,10 +23,16 @@
#include "resolved-manager.h"
-int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string);
int manager_parse_config_file(Manager *m);
+int manager_add_search_domain_by_string(Manager *m, const char *domain);
+int manager_parse_search_domains_and_warn(Manager *m, const char *string);
+
+int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word);
+int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string);
+
const struct ConfigPerfItem* resolved_gperf_lookup(const char *key, unsigned length);
-int config_parse_dnsv(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_dns_servers(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_search_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_support(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h
index 086d111205..be29f51663 100644
--- a/src/resolve/resolved-def.h
+++ b/src/resolve/resolved-def.h
@@ -21,10 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#define SD_RESOLVED_DNS ((uint64_t) 1)
-#define SD_RESOLVED_LLMNR_IPV4 ((uint64_t) 2)
-#define SD_RESOLVED_LLMNR_IPV6 ((uint64_t) 4)
-#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6)
+#define SD_RESOLVED_DNS (UINT64_C(1) << 0)
+#define SD_RESOLVED_LLMNR_IPV4 (UINT64_C(1) << 1)
+#define SD_RESOLVED_LLMNR_IPV6 (UINT64_C(1) << 2)
+#define SD_RESOLVED_NO_CNAME (UINT64_C(1) << 5)
+#define SD_RESOLVED_NO_TXT (UINT64_C(1) << 6)
+#define SD_RESOLVED_NO_ADDRESS (UINT64_C(1) << 7)
+#define SD_RESOLVED_NO_SEARCH (UINT64_C(1) << 8)
-#define SD_RESOLVED_FLAGS_ALL (SD_RESOLVED_DNS|SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6)
-#define SD_RESOLVED_FLAGS_DEFAULT SD_RESOLVED_FLAGS_ALL
+#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6)
+#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_LLMNR|SD_RESOLVED_DNS)
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index 3cf9c68074..4db67f7278 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/resolved-dns-answer.c
@@ -141,7 +141,7 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
return 0;
for (i = 0; i < a->n_rrs; i++) {
- r = dns_resource_key_match_rr(key, a->items[i].rr);
+ r = dns_resource_key_match_rr(key, a->items[i].rr, NULL);
if (r < 0)
return r;
if (r > 0)
diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h
index 044d73b19c..8814919deb 100644
--- a/src/resolve/resolved-dns-answer.h
+++ b/src/resolve/resolved-dns-answer.h
@@ -58,3 +58,20 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local);
int dns_answer_reserve(DnsAnswer **a, unsigned n_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref);
+
+#define DNS_ANSWER_FOREACH(kk, a) \
+ for (unsigned _i = ({ \
+ (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \
+ 0; \
+ }); \
+ (a) && ((_i) < (a)->n_rrs); \
+ _i++, (kk) = (_i < (a)->n_rrs ? (a)->items[_i].rr : NULL))
+
+#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a) \
+ for (unsigned _i = ({ \
+ (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \
+ (ifindex) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \
+ 0; \
+ }); \
+ (a) && ((_i) < (a)->n_rrs); \
+ _i++, (kk) = ((_i < (a)->n_rrs) ? (a)->items[_i].rr : NULL), (ifindex) = ((_i < (a)->n_rrs) ? (a)->items[_i].ifindex : 0))
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 04f64022e0..d963ce6e00 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -20,8 +20,10 @@
***/
#include "alloc-util.h"
+#include "dns-domain.h"
#include "resolved-dns-cache.h"
#include "resolved-dns-packet.h"
+#include "string-util.h"
/* Never cache more than 1K entries */
#define CACHE_MAX 1024
@@ -521,25 +523,53 @@ fail:
static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceKey *k) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *cname_key = NULL;
- DnsCacheItem *i, *j;
+ DnsCacheItem *i;
+ const char *n;
+ int r;
assert(c);
assert(k);
+ /* If we hit some OOM error, or suchlike, we don't care too
+ * much, after all this is just a cache */
+
i = hashmap_get(c->by_key, k);
- if (i || k->type == DNS_TYPE_CNAME)
+ if (i || k->type == DNS_TYPE_CNAME || k->type == DNS_TYPE_DNAME)
return i;
- /* check if we have a CNAME record instead */
+ /* Check if we have a CNAME record instead */
cname_key = dns_resource_key_new_cname(k);
if (!cname_key)
return NULL;
- j = hashmap_get(c->by_key, cname_key);
- if (j)
- return j;
+ i = hashmap_get(c->by_key, cname_key);
+ if (i)
+ return i;
+
+ /* OK, let's look for cached DNAME records. */
+ n = DNS_RESOURCE_KEY_NAME(k);
+ for (;;) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *dname_key = NULL;
+ char label[DNS_LABEL_MAX];
+
+ if (isempty(n))
+ return NULL;
- return i;
+ dname_key = dns_resource_key_new(k->class, DNS_TYPE_DNAME, n);
+ if (!dname_key)
+ return NULL;
+
+ i = hashmap_get(c->by_key, dname_key);
+ if (i)
+ return i;
+
+ /* Jump one label ahead */
+ r = dns_label_unescape(&n, label, sizeof(label));
+ if (r <= 0)
+ return NULL;
+ }
+
+ return NULL;
}
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) {
diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h
index 60cf6a4784..164435b4fb 100644
--- a/src/resolve/resolved-dns-cache.h
+++ b/src/resolve/resolved-dns-cache.h
@@ -23,18 +23,18 @@
#include "hashmap.h"
+#include "list.h"
#include "prioq.h"
#include "time-util.h"
-#include "list.h"
typedef struct DnsCache {
Hashmap *by_key;
Prioq *by_expiry;
} DnsCache;
-#include "resolved-dns-rr.h"
-#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
+#include "resolved-dns-question.h"
+#include "resolved-dns-rr.h"
void dns_cache_flush(DnsCache *c);
void dns_cache_prune(DnsCache *c);
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index f23b3cf893..40b662246f 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -370,6 +370,28 @@ int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
return 0;
}
+int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start) {
+ void *d;
+ int r;
+
+ assert(p);
+ assert(s || size == 0);
+
+ if (size > 255)
+ return -E2BIG;
+
+ r = dns_packet_extend(p, 1 + size, &d, start);
+ if (r < 0)
+ return r;
+
+ ((uint8_t*) d)[0] = (uint8_t) size;
+
+ if (size > 0)
+ memcpy(((uint8_t*) d) + 1, s, size);
+
+ return 0;
+}
+
int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
void *w;
int r;
@@ -643,19 +665,20 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
- case DNS_TYPE_TXT: {
- char **s;
+ case DNS_TYPE_TXT:
- if (strv_isempty(rr->txt.strings)) {
+ if (!rr->txt.items) {
/* RFC 6763, section 6.1 suggests to generate
* single empty string for an empty array. */
- r = dns_packet_append_string(p, "", NULL);
+ r = dns_packet_append_raw_string(p, NULL, 0, NULL);
if (r < 0)
goto fail;
} else {
- STRV_FOREACH(s, rr->txt.strings) {
- r = dns_packet_append_string(p, *s, NULL);
+ DnsTxtItem *i;
+
+ LIST_FOREACH(items, i, rr->txt.items) {
+ r = dns_packet_append_raw_string(p, i->data, i->length, NULL);
if (r < 0)
goto fail;
}
@@ -663,7 +686,6 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = 0;
break;
- }
case DNS_TYPE_A:
r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
@@ -1062,6 +1084,35 @@ fail:
return r;
}
+int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) {
+ size_t saved_rindex;
+ uint8_t c;
+ int r;
+
+ assert(p);
+
+ saved_rindex = p->rindex;
+
+ r = dns_packet_read_uint8(p, &c, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read(p, c, ret, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (size)
+ *size = c;
+ if (start)
+ *start = saved_rindex;
+
+ return 0;
+
+fail:
+ dns_packet_rewind(p, saved_rindex);
+ return r;
+}
+
int dns_packet_read_name(
DnsPacket *p,
char **_ret,
@@ -1094,7 +1145,6 @@ int dns_packet_read_name(
/* End of name */
break;
else if (c <= 63) {
- _cleanup_free_ char *t = NULL;
const char *label;
/* Literal label */
@@ -1102,21 +1152,20 @@ int dns_packet_read_name(
if (r < 0)
goto fail;
- r = dns_label_escape(label, c, &t);
- if (r < 0)
- goto fail;
-
- if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
r = -ENOMEM;
goto fail;
}
- if (!first)
- ret[n++] = '.';
- else
+ if (first)
first = false;
+ else
+ ret[n++] = '.';
+
+ r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ goto fail;
- memcpy(ret + n, t, r);
n += r;
continue;
} else if (allow_compression && (c & 0xc0) == 0xc0) {
@@ -1412,24 +1461,37 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
if (rdlength <= 0) {
+ DnsTxtItem *i;
/* RFC 6763, section 6.1 suggests to treat
* empty TXT RRs as equivalent to a TXT record
* with a single empty string. */
- r = strv_extend(&rr->txt.strings, "");
- if (r < 0)
- goto fail;
+ i = malloc0(offsetof(DnsTxtItem, data) + 1); /* for safety reasons we add an extra NUL byte */
+ if (!i)
+ return -ENOMEM;
+
+ rr->txt.items = i;
} else {
+ DnsTxtItem *last = NULL;
+
while (p->rindex < offset + rdlength) {
- char *s;
+ DnsTxtItem *i;
+ const void *data;
+ size_t sz;
- r = dns_packet_read_string(p, &s, NULL);
+ r = dns_packet_read_raw_string(p, &data, &sz, NULL);
if (r < 0)
- goto fail;
+ return r;
- r = strv_consume(&rr->txt.strings, s);
- if (r < 0)
- goto fail;
+ i = malloc0(offsetof(DnsTxtItem, data) + sz + 1); /* extra NUL byte at the end */
+ if (!i)
+ return -ENOMEM;
+
+ memcpy(i->data, data, sz);
+ i->length = sz;
+
+ LIST_INSERT_AFTER(items, rr->txt.items, last, i);
+ last = i;
}
}
@@ -1682,12 +1744,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- /* The types bitmap must contain at least the NSEC record itself, so an empty bitmap means
- something went wrong */
- if (bitmap_isclear(rr->nsec.types)) {
- r = -EBADMSG;
- goto fail;
- }
+ /* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself
+ * is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records
+ * without the NSEC bit set. */
break;
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index fbbabaf232..90b5a7c8bd 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -21,21 +21,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/udp.h>
#include <netinet/ip.h>
+#include <netinet/udp.h>
-#include "macro.h"
-#include "sparse-endian.h"
#include "hashmap.h"
#include "in-addr-util.h"
+#include "macro.h"
+#include "sparse-endian.h"
typedef struct DnsPacketHeader DnsPacketHeader;
typedef struct DnsPacket DnsPacket;
-#include "resolved-dns-rr.h"
-#include "resolved-dns-question.h"
-#include "resolved-dns-answer.h"
#include "resolved-def.h"
+#include "resolved-dns-answer.h"
+#include "resolved-dns-question.h"
+#include "resolved-dns-rr.h"
typedef enum DnsProtocol {
DNS_PROTOCOL_DNS,
@@ -155,9 +155,9 @@ int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start);
int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start);
int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start);
int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start);
+int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start);
int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start);
-int dns_packet_append_name(DnsPacket *p, const char *name,
- bool allow_compression, size_t *start);
+int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start);
int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start);
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start);
@@ -167,8 +167,8 @@ int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start);
int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start);
int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start);
int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start);
-int dns_packet_read_name(DnsPacket *p, char **ret,
- bool allow_compression, size_t *start);
+int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start);
+int dns_packet_read_name(DnsPacket *p, char **ret, bool allow_compression, size_t *start);
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start);
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start);
@@ -177,6 +177,14 @@ void dns_packet_rewind(DnsPacket *p, size_t idx);
int dns_packet_skip_question(DnsPacket *p);
int dns_packet_extract(DnsPacket *p);
+static inline bool DNS_PACKET_SHALL_CACHE(DnsPacket *p) {
+ /* Never cache data originating from localhost, under the
+ * assumption, that it's coming from a locally DNS forwarder
+ * or server, that is caching on its own. */
+
+ return in_addr_is_localhost(p->family, &p->sender) == 0;
+}
+
enum {
DNS_RCODE_SUCCESS = 0,
DNS_RCODE_FORMERR = 1,
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index f7cb84e2a6..a96cf439ad 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -30,29 +30,286 @@
#define CNAME_MAX 8
#define QUERIES_MAX 2048
+#define AUXILIARY_QUERIES_MAX 64
-static void dns_query_stop(DnsQuery *q) {
- DnsTransaction *t;
+static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
+ DnsQueryCandidate *c;
+ assert(ret);
assert(q);
+ assert(s);
- q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
+ c = new0(DnsQueryCandidate, 1);
+ if (!c)
+ return -ENOMEM;
+
+ c->query = q;
+ c->scope = s;
+
+ LIST_PREPEND(candidates_by_query, q->candidates, c);
+ LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
+
+ *ret = c;
+ return 0;
+}
- while ((t = set_steal_first(q->transactions))) {
- set_remove(t->queries, q);
+static void dns_query_candidate_stop(DnsQueryCandidate *c) {
+ DnsTransaction *t;
+
+ assert(c);
+
+ while ((t = set_steal_first(c->transactions))) {
+ set_remove(t->query_candidates, c);
dns_transaction_gc(t);
}
}
+DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
+
+ if (!c)
+ return NULL;
+
+ dns_query_candidate_stop(c);
+
+ set_free(c->transactions);
+ dns_search_domain_unref(c->search_domain);
+
+ if (c->query)
+ LIST_REMOVE(candidates_by_query, c->query->candidates, c);
+
+ if (c->scope)
+ LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
+
+ free(c);
+
+ return NULL;
+}
+
+static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
+ _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *previous = NULL;
+ DnsSearchDomain *next = NULL;
+
+ assert(c);
+
+ if (c->search_domain && c->search_domain->linked) {
+ next = c->search_domain->domains_next;
+
+ if (!next) /* We hit the end of the list */
+ return 0;
+
+ } else {
+ next = dns_scope_get_search_domains(c->scope);
+
+ if (!next) /* OK, there's nothing. */
+ return 0;
+ }
+
+ dns_search_domain_unref(c->search_domain);
+ c->search_domain = dns_search_domain_ref(next);
+
+ return 1;
+}
+
+static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
+ DnsTransaction *t;
+ int r;
+
+ assert(c);
+ assert(key);
+
+ r = set_ensure_allocated(&c->transactions, NULL);
+ if (r < 0)
+ return r;
+
+ t = dns_scope_find_transaction(c->scope, key, true);
+ if (!t) {
+ r = dns_transaction_new(&t, c->scope, key);
+ if (r < 0)
+ return r;
+ }
+
+ r = set_ensure_allocated(&t->query_candidates, NULL);
+ if (r < 0)
+ goto gc;
+
+ r = set_put(t->query_candidates, c);
+ if (r < 0)
+ goto gc;
+
+ r = set_put(c->transactions, t);
+ if (r < 0) {
+ set_remove(t->query_candidates, c);
+ goto gc;
+ }
+
+ return 0;
+
+gc:
+ dns_transaction_gc(t);
+ return r;
+}
+
+static int dns_query_candidate_go(DnsQueryCandidate *c) {
+ DnsTransaction *t;
+ Iterator i;
+ int r;
+
+ assert(c);
+
+ /* Start the transactions that are not started yet */
+ SET_FOREACH(t, c->transactions, i) {
+ if (t->state != DNS_TRANSACTION_NULL)
+ continue;
+
+ r = dns_transaction_go(t);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
+ DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
+ DnsTransaction *t;
+ Iterator i;
+
+ assert(c);
+
+ if (c->error_code != 0)
+ return DNS_TRANSACTION_RESOURCES;
+
+ SET_FOREACH(t, c->transactions, i) {
+
+ switch (t->state) {
+
+ case DNS_TRANSACTION_PENDING:
+ case DNS_TRANSACTION_NULL:
+ return t->state;
+
+ case DNS_TRANSACTION_SUCCESS:
+ state = t->state;
+ break;
+
+ default:
+ if (state != DNS_TRANSACTION_SUCCESS)
+ state = t->state;
+
+ break;
+ }
+ }
+
+ return state;
+}
+
+static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
+ DnsResourceKey *key;
+ int n = 0, r;
+
+ assert(c);
+
+ dns_query_candidate_stop(c);
+
+ /* Create one transaction per question key */
+ DNS_QUESTION_FOREACH(key, c->query->question) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
+
+ if (c->search_domain) {
+ r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = dns_query_candidate_add_transaction(c, new_key ?: key);
+ if (r < 0)
+ goto fail;
+
+ n++;
+ }
+
+ return n;
+
+fail:
+ dns_query_candidate_stop(c);
+ return r;
+}
+
+void dns_query_candidate_ready(DnsQueryCandidate *c) {
+ DnsTransactionState state;
+ int r;
+
+ assert(c);
+
+ state = dns_query_candidate_state(c);
+
+ if (IN_SET(state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL))
+ return;
+
+ if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
+
+ r = dns_query_candidate_next_search_domain(c);
+ if (r < 0)
+ goto fail;
+
+ if (r > 0) {
+ /* OK, there's another search domain to try, let's do so. */
+
+ r = dns_query_candidate_setup_transactions(c);
+ if (r < 0)
+ goto fail;
+
+ if (r > 0) {
+ /* New transactions where queued. Start them and wait */
+
+ r = dns_query_candidate_go(c);
+ if (r < 0)
+ goto fail;
+
+ return;
+ }
+ }
+
+ }
+
+ dns_query_ready(c->query);
+ return;
+
+fail:
+ log_warning_errno(r, "Failed to follow search domains: %m");
+ c->error_code = r;
+ dns_query_ready(c->query);
+}
+
+static void dns_query_stop(DnsQuery *q) {
+ DnsQueryCandidate *c;
+
+ assert(q);
+
+ q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
+
+ LIST_FOREACH(candidates_by_query, c, q->candidates)
+ dns_query_candidate_stop(c);
+}
+
DnsQuery *dns_query_free(DnsQuery *q) {
if (!q)
return NULL;
- dns_query_stop(q);
- set_free(q->transactions);
+ while (q->auxiliary_queries)
+ dns_query_free(q->auxiliary_queries);
+
+ if (q->auxiliary_for) {
+ assert(q->auxiliary_for->n_auxiliary_queries > 0);
+ q->auxiliary_for->n_auxiliary_queries--;
+ LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
+ }
+
+ while (q->candidates)
+ dns_query_candidate_free(q->candidates);
dns_question_unref(q->question);
dns_answer_unref(q->answer);
+ dns_search_domain_unref(q->answer_search_domain);
sd_bus_message_unref(q->request);
sd_bus_track_unref(q->bus_track);
@@ -75,7 +332,7 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex
assert(m);
assert(question);
- r = dns_question_is_valid(question);
+ r = dns_question_is_valid_for_query(question);
if (r < 0)
return r;
@@ -89,6 +346,8 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex
q->question = dns_question_ref(question);
q->ifindex = ifindex;
q->flags = flags;
+ q->answer_family = AF_UNSPEC;
+ q->answer_protocol = _DNS_PROTOCOL_INVALID;
for (i = 0; i < question->n_keys; i++) {
_cleanup_free_ char *p;
@@ -111,6 +370,29 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex
return 0;
}
+int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
+ assert(q);
+ assert(auxiliary_for);
+
+ /* Ensure that that the query is not auxiliary yet, and
+ * nothing else is auxiliary to it either */
+ assert(!q->auxiliary_for);
+ assert(!q->auxiliary_queries);
+
+ /* Ensure that the unit we shall be made auxiliary for isn't
+ * auxiliary itself */
+ assert(!auxiliary_for->auxiliary_for);
+
+ if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
+ return -EAGAIN;
+
+ LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
+ q->auxiliary_for = auxiliary_for;
+
+ auxiliary_for->n_auxiliary_queries++;
+ return 0;
+}
+
static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
assert(q);
assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
@@ -137,64 +419,40 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
return 0;
}
-static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
- DnsTransaction *t;
+static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
+ DnsQueryCandidate *c;
int r;
assert(q);
assert(s);
- assert(key);
- r = set_ensure_allocated(&q->transactions, NULL);
+ r = dns_query_candidate_new(&c, q, s);
if (r < 0)
return r;
- t = dns_scope_find_transaction(s, key, true);
- if (!t) {
- r = dns_transaction_new(&t, s, key);
- if (r < 0)
- return r;
- }
-
- r = set_ensure_allocated(&t->queries, NULL);
+ /* If this a single-label domain on DNS, we might append a suitable search domain first. */
+ r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question));
if (r < 0)
- goto gc;
-
- r = set_put(t->queries, q);
- if (r < 0)
- goto gc;
+ goto fail;
+ if (r > 0) {
+ /* OK, we need a search domain now. Let's find one for this scope */
- r = set_put(q->transactions, t);
- if (r < 0) {
- set_remove(t->queries, q);
- goto gc;
+ r = dns_query_candidate_next_search_domain(c);
+ if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
+ goto fail;
}
+ r = dns_query_candidate_setup_transactions(c);
+ if (r < 0)
+ goto fail;
+
return 0;
-gc:
- dns_transaction_gc(t);
+fail:
+ dns_query_candidate_free(c);
return r;
}
-static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
- unsigned i;
- int r;
-
- assert(q);
- assert(s);
-
- /* Create one transaction per question key */
-
- for (i = 0; i < q->question->n_keys; i++) {
- r = dns_query_add_transaction(q, s, q->question->keys[i]);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
static int SYNTHESIZE_IFINDEX(int ifindex) {
/* When the caller asked for resolving on a specific
@@ -597,9 +855,9 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
q->answer = answer;
answer = NULL;
- q->answer_family = SYNTHESIZE_FAMILY(q->flags);
- q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
q->answer_rcode = DNS_RCODE_SUCCESS;
+ q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
+ q->answer_family = SYNTHESIZE_FAMILY(q->flags);
*state = DNS_TRANSACTION_SUCCESS;
@@ -609,9 +867,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
int dns_query_go(DnsQuery *q) {
DnsScopeMatch found = DNS_SCOPE_NO;
DnsScope *s, *first = NULL;
- DnsTransaction *t;
+ DnsQueryCandidate *c;
const char *name;
- Iterator i;
int r;
assert(q);
@@ -622,7 +879,7 @@ int dns_query_go(DnsQuery *q) {
assert(q->question);
assert(q->question->n_keys > 0);
- name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
+ name = dns_question_first_name(q->question);
LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
DnsScopeMatch match;
@@ -655,7 +912,7 @@ int dns_query_go(DnsQuery *q) {
return 1;
}
- r = dns_query_add_transaction_split(q, first);
+ r = dns_query_add_candidate(q, first);
if (r < 0)
goto fail;
@@ -669,7 +926,7 @@ int dns_query_go(DnsQuery *q) {
if (match != found)
continue;
- r = dns_query_add_transaction_split(q, s);
+ r = dns_query_add_candidate(q, s);
if (r < 0)
goto fail;
}
@@ -691,14 +948,13 @@ int dns_query_go(DnsQuery *q) {
q->state = DNS_TRANSACTION_PENDING;
q->block_ready++;
- /* Start the transactions that are not started yet */
- SET_FOREACH(t, q->transactions, i) {
- if (t->state != DNS_TRANSACTION_NULL)
- continue;
-
- r = dns_transaction_go(t);
- if (r < 0)
+ /* Start the transactions */
+ LIST_FOREACH(candidates_by_query, c, q->candidates) {
+ r = dns_query_candidate_go(c);
+ if (r < 0) {
+ q->block_ready--;
goto fail;
+ }
}
q->block_ready--;
@@ -711,132 +967,128 @@ fail:
return r;
}
-void dns_query_ready(DnsQuery *q) {
- DnsTransaction *t;
+static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- int rcode = 0;
- DnsScope *scope = NULL;
- bool pending = false;
+ DnsTransaction *t;
Iterator i;
assert(q);
- assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
- /* Note that this call might invalidate the query. Callers
- * should hence not attempt to access the query or transaction
- * after calling this function, unless the block_ready
- * counter was explicitly bumped before doing so. */
-
- if (q->block_ready > 0)
+ if (!c) {
+ dns_query_synthesize_reply(q, &state);
+ dns_query_complete(q, state);
return;
+ }
- SET_FOREACH(t, q->transactions, i) {
+ SET_FOREACH(t, c->transactions, i) {
- /* If we found a successful answer, ignore all answers from other scopes */
- if (state == DNS_TRANSACTION_SUCCESS && t->scope != scope)
- continue;
+ switch (t->state) {
- /* One of the transactions is still going on, let's maybe wait for it */
- if (IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL)) {
- pending = true;
- continue;
- }
+ case DNS_TRANSACTION_SUCCESS: {
+ /* We found a successfuly reply, merge it into the answer */
+ DnsAnswer *merged;
- /* One of the transactions is successful, let's use
- * it, and copy its data out */
- if (t->state == DNS_TRANSACTION_SUCCESS) {
- DnsAnswer *a;
-
- if (t->received) {
- rcode = DNS_PACKET_RCODE(t->received);
- a = t->received->answer;
- } else {
- rcode = t->cached_rcode;
- a = t->cached;
+ merged = dns_answer_merge(q->answer, t->answer);
+ if (!merged) {
+ dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
+ return;
}
- if (state == DNS_TRANSACTION_SUCCESS) {
- DnsAnswer *merged;
+ dns_answer_unref(q->answer);
+ q->answer = merged;
+ q->answer_rcode = t->answer_rcode;
+
+ state = DNS_TRANSACTION_SUCCESS;
+ break;
+ }
+
+ case DNS_TRANSACTION_PENDING:
+ case DNS_TRANSACTION_NULL:
+ case DNS_TRANSACTION_ABORTED:
+ /* Ignore transactions that didn't complete */
+ continue;
+
+ default:
+ /* Any kind of failure? Store the data away,
+ * if there's nothing stored yet. */
- merged = dns_answer_merge(answer, a);
- if (!merged) {
- dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
- return;
- }
+ if (state != DNS_TRANSACTION_SUCCESS) {
- dns_answer_unref(answer);
- answer = merged;
- } else {
- dns_answer_unref(answer);
- answer = dns_answer_ref(a);
+ dns_answer_unref(q->answer);
+ q->answer = dns_answer_ref(t->answer);
+ q->answer_rcode = t->answer_rcode;
+
+ state = t->state;
}
- scope = t->scope;
- state = DNS_TRANSACTION_SUCCESS;
- continue;
+ break;
}
+ }
- /* One of the transactions has failed, let's see
- * whether we find anything better, but if not, return
- * its response data */
- if (state != DNS_TRANSACTION_SUCCESS && t->state == DNS_TRANSACTION_FAILURE) {
- DnsAnswer *a;
-
- if (t->received) {
- rcode = DNS_PACKET_RCODE(t->received);
- a = t->received->answer;
- } else {
- rcode = t->cached_rcode;
- a = t->cached;
- }
+ q->answer_protocol = c->scope->protocol;
+ q->answer_family = c->scope->family;
- dns_answer_unref(answer);
- answer = dns_answer_ref(a);
+ dns_search_domain_unref(q->answer_search_domain);
+ q->answer_search_domain = dns_search_domain_ref(c->search_domain);
- scope = t->scope;
- state = DNS_TRANSACTION_FAILURE;
- continue;
- }
+ dns_query_synthesize_reply(q, &state);
+ dns_query_complete(q, state);
+}
- if (state == DNS_TRANSACTION_NO_SERVERS && t->state != DNS_TRANSACTION_NO_SERVERS)
- state = t->state;
- }
+void dns_query_ready(DnsQuery *q) {
+
+ DnsQueryCandidate *bad = NULL, *c;
+ bool pending = false;
- if (pending) {
+ assert(q);
+ assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
- /* If so far we weren't successful, and there's
- * something still pending, then wait for it */
- if (state != DNS_TRANSACTION_SUCCESS)
+ /* Note that this call might invalidate the query. Callers
+ * should hence not attempt to access the query or transaction
+ * after calling this function, unless the block_ready
+ * counter was explicitly bumped before doing so. */
+
+ if (q->block_ready > 0)
+ return;
+
+ LIST_FOREACH(candidates_by_query, c, q->candidates) {
+ DnsTransactionState state;
+
+ state = dns_query_candidate_state(c);
+ switch (state) {
+
+ case DNS_TRANSACTION_SUCCESS:
+ /* One of the transactions is successful,
+ * let's use it, and copy its data out */
+ dns_query_accept(q, c);
return;
- /* If we already were successful, then only wait for
- * other transactions on the same scope to finish. */
- SET_FOREACH(t, q->transactions, i) {
- if (t->scope == scope && IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL))
- return;
- }
- }
+ case DNS_TRANSACTION_PENDING:
+ case DNS_TRANSACTION_NULL:
+ /* One of the transactions is still going on, let's maybe wait for it */
+ pending = true;
+ break;
- if (IN_SET(state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE)) {
- q->answer = dns_answer_ref(answer);
- q->answer_rcode = rcode;
- q->answer_protocol = scope ? scope->protocol : _DNS_PROTOCOL_INVALID;
- q->answer_family = scope ? scope->family : AF_UNSPEC;
+ default:
+ /* Any kind of failure */
+ bad = c;
+ break;
+ }
}
- /* Try to synthesize a reply if we couldn't resolve something. */
- dns_query_synthesize_reply(q, &state);
+ if (pending)
+ return;
- dns_query_complete(q, state);
+ dns_query_accept(q, bad);
}
-int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
+static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
_cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
int r;
assert(q);
+ q->n_cname_redirects ++;
if (q->n_cname_redirects > CNAME_MAX)
return -ELOOP;
@@ -848,14 +1100,66 @@ int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
q->question = nq;
nq = NULL;
- q->n_cname_redirects++;
-
dns_query_stop(q);
q->state = DNS_TRANSACTION_NULL;
return 0;
}
+int dns_query_process_cname(DnsQuery *q) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
+ DnsResourceRecord *rr;
+ int r;
+
+ assert(q);
+
+ if (q->state != DNS_TRANSACTION_SUCCESS)
+ return 0;
+
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+
+ r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0; /* The answer matches directly, no need to follow cnames */
+
+ r = dns_question_matches_cname(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
+ if (r < 0)
+ return r;
+ if (r > 0 && !cname)
+ cname = dns_resource_record_ref(rr);
+ }
+
+ if (!cname)
+ return 0; /* No cname to follow */
+
+ if (q->flags & SD_RESOLVED_NO_CNAME)
+ return -ELOOP;
+
+ /* OK, let's actually follow the CNAME */
+ r = dns_query_cname_redirect(q, cname);
+ if (r < 0)
+ return r;
+
+ /* Let's see if the answer can already answer the new
+ * redirected question */
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+ r = dns_question_matches_rr(q->question, rr, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0; /* It can answer it, yay! */
+ }
+
+ /* OK, it cannot, let's begin with the new query */
+ r = dns_query_go(q);
+ if (r < 0)
+ return r;
+
+ return 1; /* We return > 0, if we restarted the query for a new cname */
+}
+
static int on_bus_track(sd_bus_track *t, void *userdata) {
DnsQuery *q = userdata;
diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h
index e7063d9678..a9d7904a8d 100644
--- a/src/resolve/resolved-dns-query.h
+++ b/src/resolve/resolved-dns-query.h
@@ -23,56 +23,88 @@
#include "sd-bus.h"
+
#include "set.h"
+typedef struct DnsQueryCandidate DnsQueryCandidate;
typedef struct DnsQuery DnsQuery;
-#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
+#include "resolved-dns-question.h"
#include "resolved-dns-stream.h"
+#include "resolved-dns-search-domain.h"
+
+struct DnsQueryCandidate {
+ DnsQuery *query;
+ DnsScope *scope;
+
+ DnsSearchDomain *search_domain;
+
+ int error_code;
+ Set *transactions;
+
+ LIST_FIELDS(DnsQueryCandidate, candidates_by_query);
+ LIST_FIELDS(DnsQueryCandidate, candidates_by_scope);
+};
struct DnsQuery {
Manager *manager;
- DnsQuestion *question;
+ /* When resolving a service, we first create a TXT+SRV query,
+ * and then for the hostnames we discover auxiliary A+AAAA
+ * queries. This pointer always points from the auxiliary
+ * queries back to the TXT+SRV query. */
+ DnsQuery *auxiliary_for;
+ LIST_HEAD(DnsQuery, auxiliary_queries);
+ unsigned n_auxiliary_queries;
+ int auxiliary_result;
+
+ DnsQuestion *question;
uint64_t flags;
int ifindex;
DnsTransactionState state;
unsigned n_cname_redirects;
+ LIST_HEAD(DnsQueryCandidate, candidates);
sd_event_source *timeout_event_source;
/* Discovered data */
DnsAnswer *answer;
- int answer_family;
- DnsProtocol answer_protocol;
int answer_rcode;
+ DnsProtocol answer_protocol;
+ int answer_family;
+ DnsSearchDomain *answer_search_domain;
/* Bus client information */
sd_bus_message *request;
int request_family;
- const char *request_hostname;
+ bool request_address_valid;
union in_addr_union request_address;
+ unsigned block_all_complete;
/* Completion callback */
void (*complete)(DnsQuery* q);
unsigned block_ready;
- Set *transactions;
-
sd_bus_track *bus_track;
LIST_FIELDS(DnsQuery, queries);
+ LIST_FIELDS(DnsQuery, auxiliary_queries);
};
+DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c);
+void dns_query_candidate_ready(DnsQueryCandidate *c);
+
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question, int family, uint64_t flags);
DnsQuery *dns_query_free(DnsQuery *q);
+int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for);
+
int dns_query_go(DnsQuery *q);
void dns_query_ready(DnsQuery *q);
-int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname);
+int dns_query_process_cname(DnsQuery *q);
int dns_query_bus_track(DnsQuery *q, sd_bus_message *m);
diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c
index 48951221dc..3249448d3b 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/resolved-dns-question.c
@@ -89,7 +89,7 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
return 0;
}
-int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
+int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
unsigned i;
int r;
@@ -99,7 +99,7 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
return 0;
for (i = 0; i < q->n_keys; i++) {
- r = dns_resource_key_match_rr(q->keys[i], rr);
+ r = dns_resource_key_match_rr(q->keys[i], rr, search_domain);
if (r != 0)
return r;
}
@@ -107,7 +107,7 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
return 0;
}
-int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
+int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
unsigned i;
int r;
@@ -117,7 +117,7 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
return 0;
for (i = 0; i < q->n_keys; i++) {
- r = dns_resource_key_match_cname(q->keys[i], rr);
+ r = dns_resource_key_match_cname(q->keys[i], rr, search_domain);
if (r != 0)
return r;
}
@@ -125,7 +125,7 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
return 0;
}
-int dns_question_is_valid(DnsQuestion *q) {
+int dns_question_is_valid_for_query(DnsQuestion *q) {
const char *name;
unsigned i;
int r;
@@ -155,50 +155,6 @@ int dns_question_is_valid(DnsQuestion *q) {
return 1;
}
-int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
- unsigned j;
- int r;
-
- /* Checks if all keys in "other" are also contained in "q" */
-
- if (!other)
- return 1;
-
- for (j = 0; j < other->n_keys; j++) {
- DnsResourceKey *b = other->keys[j];
- bool found = false;
- unsigned i;
-
- if (!q)
- return 0;
-
- for (i = 0; i < q->n_keys; i++) {
- DnsResourceKey *a = q->keys[i];
-
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
- if (r < 0)
- return r;
-
- if (r == 0)
- continue;
-
- if (a->class != b->class && a->class != DNS_CLASS_ANY)
- continue;
-
- if (a->type != b->type && a->type != DNS_TYPE_ANY)
- continue;
-
- found = true;
- break;
- }
-
- if (!found)
- return 0;
- }
-
- return 1;
-}
-
int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
unsigned j;
int r;
@@ -251,6 +207,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
assert(cname);
assert(ret);
+ assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
if (!q) {
n = dns_question_new(0);
@@ -263,7 +220,22 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
}
for (i = 0; i < q->n_keys; i++) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.name);
+ _cleanup_free_ char *destination = NULL;
+ const char *d;
+
+ if (cname->key->type == DNS_TYPE_CNAME)
+ d = cname->cname.name;
+ else {
+ r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(q->keys[i]), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ d = destination;
+ }
+
+ r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), d);
if (r < 0)
return r;
@@ -301,3 +273,131 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
return 1;
}
+
+const char *dns_question_first_name(DnsQuestion *q) {
+
+ if (!q)
+ return NULL;
+
+ if (q->n_keys < 1)
+ return NULL;
+
+ return DNS_RESOURCE_KEY_NAME(q->keys[0]);
+}
+
+int dns_question_new_address(DnsQuestion **ret, int family, const char *name) {
+ _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
+ int r;
+
+ assert(ret);
+ assert(name);
+
+ if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
+ return -EAFNOSUPPORT;
+
+ q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
+ if (!q)
+ return -ENOMEM;
+
+ if (family != AF_INET6) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+
+ key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name);
+ if (!key)
+ return -ENOMEM;
+
+ r = dns_question_add(q, key);
+ if (r < 0)
+ return r;
+ }
+
+ if (family != AF_INET) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+
+ key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
+ if (!key)
+ return -ENOMEM;
+
+ r = dns_question_add(q, key);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = q;
+ q = NULL;
+
+ return 0;
+}
+
+int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+ _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
+ _cleanup_free_ char *reverse = NULL;
+ int r;
+
+ assert(ret);
+ assert(a);
+
+ if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
+ return -EAFNOSUPPORT;
+
+ r = dns_name_reverse(family, a, &reverse);
+ if (r < 0)
+ return r;
+
+ q = dns_question_new(1);
+ if (!q)
+ return -ENOMEM;
+
+ key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
+ if (!key)
+ return -ENOMEM;
+
+ reverse = NULL;
+
+ r = dns_question_add(q, key);
+ if (r < 0)
+ return r;
+
+ *ret = q;
+ q = NULL;
+
+ return 0;
+}
+
+int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+ _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
+ int r;
+
+ assert(ret);
+ assert(name);
+
+ q = dns_question_new(1 + with_txt);
+ if (!q)
+ return -ENOMEM;
+
+ key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name);
+ if (!key)
+ return -ENOMEM;
+
+ r = dns_question_add(q, key);
+ if (r < 0)
+ return r;
+
+ if (with_txt) {
+ dns_resource_key_unref(key);
+ key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name);
+ if (!key)
+ return -ENOMEM;
+
+ r = dns_question_add(q, key);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = q;
+ q = NULL;
+
+ return 0;
+}
diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h
index 13cd1f20f3..e77116c03a 100644
--- a/src/resolve/resolved-dns-question.h
+++ b/src/resolve/resolved-dns-question.h
@@ -37,15 +37,28 @@ DnsQuestion *dns_question_new(unsigned n);
DnsQuestion *dns_question_ref(DnsQuestion *q);
DnsQuestion *dns_question_unref(DnsQuestion *q);
+int dns_question_new_address(DnsQuestion **ret, int family, const char *name);
+int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a);
+int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt);
+
int dns_question_add(DnsQuestion *q, DnsResourceKey *key);
-int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr);
-int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr);
-int dns_question_is_valid(DnsQuestion *q);
-int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other);
+int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain);
+int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr, const char* search_domain);
+int dns_question_is_valid_for_query(DnsQuestion *q);
int dns_question_contains(DnsQuestion *a, DnsResourceKey *k);
int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b);
int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret);
+const char *dns_question_first_name(DnsQuestion *q);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref);
+
+#define DNS_QUESTION_FOREACH(key, q) \
+ for (unsigned _i = ({ \
+ (key) = ((q) && (q)->n_keys > 0) ? (q)->keys[0] : NULL; \
+ 0; \
+ }); \
+ (q) && ((_i) < (q)->n_keys); \
+ _i++, (key) = (_i < (q)->n_keys ? (q)->keys[_i] : NULL))
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index ba2ea686f3..4a1abb0cdc 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -57,10 +57,61 @@ DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) {
}
DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
+ int r;
+
assert(key);
assert(cname);
- return dns_resource_key_new(key->class, key->type, cname->cname.name);
+ assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
+
+ if (cname->key->type == DNS_TYPE_CNAME)
+ return dns_resource_key_new(key->class, key->type, cname->cname.name);
+ else {
+ DnsResourceKey *k;
+ char *destination = NULL;
+
+ r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ if (r < 0)
+ return NULL;
+ if (r == 0)
+ return dns_resource_key_ref((DnsResourceKey*) key);
+
+ k = dns_resource_key_new_consume(key->class, key->type, destination);
+ if (!k) {
+ free(destination);
+ return NULL;
+ }
+
+ return k;
+ }
+}
+
+int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
+ DnsResourceKey *new_key;
+ char *joined;
+ int r;
+
+ assert(ret);
+ assert(key);
+ assert(name);
+
+ if (dns_name_is_root(name)) {
+ *ret = dns_resource_key_ref(key);
+ return 0;
+ }
+
+ r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
+ if (r < 0)
+ return r;
+
+ new_key = dns_resource_key_new_consume(key->class, key->type, joined);
+ if (!new_key) {
+ free(joined);
+ return -ENOMEM;
+ }
+
+ *ret = new_key;
+ return 0;
}
DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
@@ -122,30 +173,73 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
return 1;
}
-int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
+int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
+ int r;
+
assert(key);
assert(rr);
+ /* Checks if an rr matches the specified key. If a search
+ * domain is specified, it will also be checked if the key
+ * with the search domain suffixed might match the RR. */
+
if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
return 0;
if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+ r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+ if (r != 0)
+ return r;
+
+ if (search_domain) {
+ _cleanup_free_ char *joined = NULL;
+
+ r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ if (r < 0)
+ return r;
+
+ return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
+ }
+
+ return 0;
}
-int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
+int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
+ int r;
+
assert(key);
assert(rr);
if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
return 0;
- if (rr->key->type != DNS_TYPE_CNAME)
+ if (rr->key->type == DNS_TYPE_CNAME)
+ r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
+ else if (rr->key->type == DNS_TYPE_DNAME)
+ r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
+ else
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+ if (r != 0)
+ return r;
+
+ if (search_domain) {
+ _cleanup_free_ char *joined = NULL;
+
+ r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ if (r < 0)
+ return r;
+
+ if (rr->key->type == DNS_TYPE_CNAME)
+ return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key));
+ else if (rr->key->type == DNS_TYPE_DNAME)
+ return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key));
+ }
+
+ return 0;
+
}
static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
@@ -273,7 +367,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
case DNS_TYPE_TXT:
case DNS_TYPE_SPF:
- strv_free(rr->txt.strings);
+ dns_txt_item_free_all(rr->txt.items);
break;
case DNS_TYPE_SOA:
@@ -430,7 +524,7 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
- return strv_equal(a->txt.strings, b->txt.strings);
+ return dns_txt_item_equal(a->txt.items, b->txt.items);
case DNS_TYPE_A:
return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
@@ -600,6 +694,43 @@ static char *format_types(Bitmap *types) {
return strjoin("( ", str, " )", NULL);
}
+static char *format_txt(DnsTxtItem *first) {
+ DnsTxtItem *i;
+ size_t c = 1;
+ char *p, *s;
+
+ LIST_FOREACH(items, i, first)
+ c += i->length * 4 + 3;
+
+ p = s = new(char, c);
+ if (!s)
+ return NULL;
+
+ LIST_FOREACH(items, i, first) {
+ size_t j;
+
+ if (i != first)
+ *(p++) = ' ';
+
+ *(p++) = '"';
+
+ for (j = 0; j < i->length; j++) {
+ if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
+ *(p++) = '\\';
+ *(p++) = '0' + (i->data[j] / 100);
+ *(p++) = '0' + ((i->data[j] / 10) % 10);
+ *(p++) = '0' + (i->data[j] % 10);
+ } else
+ *(p++) = i->data[j];
+ }
+
+ *(p++) = '"';
+ }
+
+ *p = 0;
+ return s;
+}
+
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
_cleanup_free_ char *k = NULL, *t = NULL;
char *s;
@@ -642,14 +773,13 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
- t = strv_join_quoted(rr->txt.strings);
+ t = format_txt(rr->txt.items);
if (!t)
return -ENOMEM;
s = strjoin(k, " ", t, NULL);
if (!s)
return -ENOMEM;
-
break;
case DNS_TYPE_A: {
@@ -890,3 +1020,32 @@ int dns_class_from_string(const char *s, uint16_t *class) {
return 0;
}
+
+DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
+ DnsTxtItem *n;
+
+ if (!i)
+ return NULL;
+
+ n = i->items_next;
+
+ free(i);
+ return dns_txt_item_free_all(n);
+}
+
+bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
+
+ if (!a != !b)
+ return false;
+
+ if (!a)
+ return true;
+
+ if (a->length != b->length)
+ return false;
+
+ if (memcmp(a->data, b->data, a->length) != 0)
+ return false;
+
+ return dns_txt_item_equal(a->items_next, b->items_next);
+}
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 9e2207c0aa..f8066c06a6 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -24,12 +24,14 @@
#include <netinet/in.h>
#include "bitmap.h"
+#include "dns-type.h"
#include "hashmap.h"
#include "in-addr-util.h"
-#include "dns-type.h"
+#include "list.h"
typedef struct DnsResourceKey DnsResourceKey;
typedef struct DnsResourceRecord DnsResourceRecord;
+typedef struct DnsTxtItem DnsTxtItem;
/* DNS record classes, see RFC 1035 */
enum {
@@ -45,6 +47,12 @@ struct DnsResourceKey {
char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */
};
+struct DnsTxtItem {
+ size_t length;
+ LIST_FIELDS(DnsTxtItem, items);
+ uint8_t data[];
+};
+
struct DnsResourceRecord {
unsigned n_ref;
DnsResourceKey *key;
@@ -73,7 +81,7 @@ struct DnsResourceRecord {
} hinfo;
struct {
- char **strings;
+ DnsTxtItem *items;
} txt, spf;
struct {
@@ -178,13 +186,15 @@ static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) {
DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name);
DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key);
+DnsResourceKey* dns_resource_key_new_dname(const DnsResourceKey *key);
DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname);
+int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name);
DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name);
DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key);
DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key);
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);
-int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr);
-int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr);
+int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain);
+int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain);
int dns_resource_key_to_string(const DnsResourceKey *key, char **ret);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref);
@@ -198,6 +208,9 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref);
+DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i);
+bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b);
+
const char *dns_class_to_string(uint16_t type);
int dns_class_from_string(const char *name, uint16_t *class);
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index b15370b017..fc4ae57ce0 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -69,18 +69,12 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
return 0;
}
-DnsScope* dns_scope_free(DnsScope *s) {
- DnsTransaction *t;
- DnsResourceRecord *rr;
-
- if (!s)
- return NULL;
-
- log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
+static void dns_scope_abort_transactions(DnsScope *s) {
+ assert(s);
- dns_scope_llmnr_membership(s, false);
+ while (s->transactions) {
+ DnsTransaction *t = s->transactions;
- while ((t = hashmap_steal_first(s->transactions))) {
/* Abort the transaction, but make sure it is not
* freed while we still look at it */
@@ -90,8 +84,23 @@ DnsScope* dns_scope_free(DnsScope *s) {
dns_transaction_free(t);
}
+}
- hashmap_free(s->transactions);
+DnsScope* dns_scope_free(DnsScope *s) {
+ DnsResourceRecord *rr;
+
+ if (!s)
+ return NULL;
+
+ log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
+
+ dns_scope_llmnr_membership(s, false);
+ dns_scope_abort_transactions(s);
+
+ while (s->query_candidates)
+ dns_query_candidate_free(s->query_candidates);
+
+ hashmap_free(s->transactions_by_key);
while ((rr = ordered_hashmap_steal_first(s->conflict_queue)))
dns_resource_record_unref(rr);
@@ -103,7 +112,6 @@ DnsScope* dns_scope_free(DnsScope *s) {
dns_zone_flush(&s->zone);
LIST_REMOVE(scopes, s->manager->dns_scopes, s);
- strv_free(s->domains);
free(s);
return NULL;
@@ -136,11 +144,11 @@ void dns_scope_next_dns_server(DnsScope *s) {
void dns_scope_packet_received(DnsScope *s, usec_t rtt) {
assert(s);
- if (rtt > s->max_rtt) {
- s->max_rtt = rtt;
- s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2),
- MULTICAST_RESEND_TIMEOUT_MAX_USEC);
- }
+ if (rtt <= s->max_rtt)
+ return;
+
+ s->max_rtt = rtt;
+ s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), MULTICAST_RESEND_TIMEOUT_MAX_USEC);
}
void dns_scope_packet_lost(DnsScope *s, usec_t usec) {
@@ -323,7 +331,7 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
}
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
- char **i;
+ DnsSearchDomain *d;
assert(s);
assert(domain);
@@ -334,7 +342,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0)
return DNS_SCOPE_NO;
- if (dns_name_root(domain) != 0)
+ if (dns_name_is_root(domain))
return DNS_SCOPE_NO;
/* Never resolve any loopback hostname or IP address via DNS,
@@ -345,15 +353,22 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
return DNS_SCOPE_NO;
- STRV_FOREACH(i, s->domains)
- if (dns_name_endswith(domain, *i) > 0)
+ /* Always honour search domains for routing queries. Note that
+ * we return DNS_SCOPE_YES here, rather than just
+ * DNS_SCOPE_MAYBE, which means wildcard scopes won't be
+ * considered anymore. */
+ LIST_FOREACH(domains, d, dns_scope_get_search_domains(s))
+ if (dns_name_endswith(domain, d->name) > 0)
return DNS_SCOPE_YES;
switch (s->protocol) {
+
case DNS_PROTOCOL_DNS:
- if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
- dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
- dns_name_single_label(domain) == 0)
+
+ if ((!dns_name_is_single_label(domain) ||
+ (!(flags & SD_RESOLVED_NO_SEARCH) && dns_scope_has_search_domains(s))) &&
+ dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
+ dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0)
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
@@ -371,7 +386,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
case DNS_PROTOCOL_LLMNR:
if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
(s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) ||
- (dns_name_single_label(domain) > 0 && /* only resolve single label names via LLMNR */
+ (dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
!is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
return DNS_SCOPE_MAYBE;
@@ -543,6 +558,7 @@ static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
_cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
+ DnsResourceKey *key = NULL;
bool tentative = false;
int r, fd;
@@ -576,7 +592,10 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
return;
}
- r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
+ assert(p->question->n_keys == 1);
+ key = p->question->keys[0];
+
+ r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative);
if (r < 0) {
log_debug_errno(r, "Failed to lookup key: %m");
return;
@@ -634,7 +653,7 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key,
/* Try to find an ongoing transaction that is a equal to the
* specified question */
- t = hashmap_get(scope->transactions, key);
+ t = hashmap_get(scope->transactions_by_key, key);
if (!t)
return NULL;
@@ -642,7 +661,7 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key,
* data instead of a real packet, if that's requested. */
if (!cache_ok &&
IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
- !t->received)
+ t->answer_source != DNS_TRANSACTION_NETWORK)
return NULL;
return t;
@@ -846,3 +865,45 @@ void dns_scope_dump(DnsScope *s, FILE *f) {
dns_cache_dump(&s->cache, f);
}
}
+
+DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
+ assert(s);
+
+ /* Returns the list of *local* search domains -- not the
+ * global ones. */
+
+ if (s->protocol != DNS_PROTOCOL_DNS)
+ return NULL;
+
+ if (s->link)
+ return s->link->search_domains;
+
+ return NULL;
+}
+
+bool dns_scope_has_search_domains(DnsScope *s) {
+ assert(s);
+
+ /* Tests if there are *any* search domains suitable for this
+ * scope. This means either local or global ones */
+
+ if (s->protocol != DNS_PROTOCOL_DNS)
+ return false;
+
+ if (s->manager->search_domains)
+ return true;
+
+ if (s->link && s->link->search_domains)
+ return true;
+
+ return false;
+}
+
+bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
+ assert(s);
+
+ if (s->protocol != DNS_PROTOCOL_DNS)
+ return false;
+
+ return dns_name_is_single_label(name);
+}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index b75f212897..7876410b7d 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -25,9 +25,9 @@
typedef struct DnsScope DnsScope;
-#include "resolved-dns-server.h"
-#include "resolved-dns-packet.h"
#include "resolved-dns-cache.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-server.h"
#include "resolved-dns-zone.h"
#include "resolved-link.h"
@@ -47,8 +47,6 @@ struct DnsScope {
Link *link;
- char **domains;
-
DnsCache cache;
DnsZone zone;
@@ -60,7 +58,18 @@ struct DnsScope {
usec_t resend_timeout;
usec_t max_rtt;
- Hashmap *transactions;
+ LIST_HEAD(DnsQueryCandidate, query_candidates);
+
+ /* Note that we keep track of ongoing transactions in two
+ * ways: once in a hashmap, indexed by the rr key, and once in
+ * a linked list. We use the hashmap to quickly find
+ * transactions we can reuse for a key. But note that there
+ * might be multiple transactions for the same key (because
+ * the zone probing can't reuse a transaction answered from
+ * the zone or the cache), and the hashmap only tracks the
+ * most recent entry. */
+ Hashmap *transactions_by_key;
+ LIST_HEAD(DnsTransaction, transactions);
LIST_FIELDS(DnsScope, scopes);
};
@@ -91,3 +100,8 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr);
void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p);
void dns_scope_dump(DnsScope *s, FILE *f);
+
+DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s);
+bool dns_scope_has_search_domains(DnsScope *s);
+
+bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c
new file mode 100644
index 0000000000..f9d966abb1
--- /dev/null
+++ b/src/resolve/resolved-dns-search-domain.c
@@ -0,0 +1,232 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "dns-domain.h"
+#include "resolved-dns-search-domain.h"
+
+int dns_search_domain_new(
+ Manager *m,
+ DnsSearchDomain **ret,
+ DnsSearchDomainType type,
+ Link *l,
+ const char *name) {
+
+ _cleanup_free_ char *normalized = NULL;
+ DnsSearchDomain *d;
+ int r;
+
+ assert(m);
+ assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
+ assert(name);
+
+ r = dns_name_normalize(name, &normalized);
+ if (r < 0)
+ return r;
+
+ if (dns_name_is_root(normalized))
+ return -EINVAL;
+
+ if (l) {
+ if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
+ return -E2BIG;
+ } else {
+ if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX)
+ return -E2BIG;
+ }
+
+ d = new0(DnsSearchDomain, 1);
+ if (!d)
+ return -ENOMEM;
+
+ d->n_ref = 1;
+ d->manager = m;
+ d->type = type;
+ d->name = normalized;
+ normalized = NULL;
+
+ switch (type) {
+
+ case DNS_SEARCH_DOMAIN_LINK:
+ d->link = l;
+ LIST_APPEND(domains, l->search_domains, d);
+ l->n_search_domains++;
+ break;
+
+ case DNS_SERVER_SYSTEM:
+ LIST_APPEND(domains, m->search_domains, d);
+ m->n_search_domains++;
+ break;
+
+ default:
+ assert_not_reached("Unknown search domain type");
+ }
+
+ d->linked = true;
+
+ if (ret)
+ *ret = d;
+
+ return 0;
+}
+
+DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d) {
+ if (!d)
+ return NULL;
+
+ assert(d->n_ref > 0);
+ d->n_ref++;
+
+ return d;
+}
+
+DnsSearchDomain* dns_search_domain_unref(DnsSearchDomain *d) {
+ if (!d)
+ return NULL;
+
+ assert(d->n_ref > 0);
+ d->n_ref--;
+
+ if (d->n_ref > 0)
+ return NULL;
+
+ free(d->name);
+ free(d);
+
+ return NULL;
+}
+
+void dns_search_domain_unlink(DnsSearchDomain *d) {
+ assert(d);
+ assert(d->manager);
+
+ if (!d->linked)
+ return;
+
+ switch (d->type) {
+
+ case DNS_SEARCH_DOMAIN_LINK:
+ assert(d->link);
+ assert(d->link->n_search_domains > 0);
+ LIST_REMOVE(domains, d->link->search_domains, d);
+ d->link->n_search_domains--;
+ break;
+
+ case DNS_SEARCH_DOMAIN_SYSTEM:
+ assert(d->manager->n_search_domains > 0);
+ LIST_REMOVE(domains, d->manager->search_domains, d);
+ d->manager->n_search_domains--;
+ break;
+ }
+
+ d->linked = false;
+
+ dns_search_domain_unref(d);
+}
+
+void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) {
+ DnsSearchDomain *tail;
+
+ assert(d);
+
+ if (!d->marked)
+ return;
+
+ d->marked = false;
+
+ if (!d->linked || !d->domains_next)
+ return;
+
+ switch (d->type) {
+
+ case DNS_SEARCH_DOMAIN_LINK:
+ assert(d->link);
+ LIST_FIND_TAIL(domains, d, tail);
+ LIST_REMOVE(domains, d->link->search_domains, d);
+ LIST_INSERT_AFTER(domains, d->link->search_domains, tail, d);
+ break;
+
+ case DNS_SEARCH_DOMAIN_SYSTEM:
+ LIST_FIND_TAIL(domains, d, tail);
+ LIST_REMOVE(domains, d->manager->search_domains, d);
+ LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d);
+ break;
+
+ default:
+ assert_not_reached("Unknown search domain type");
+ }
+}
+
+void dns_search_domain_unlink_all(DnsSearchDomain *first) {
+ DnsSearchDomain *next;
+
+ if (!first)
+ return;
+
+ next = first->domains_next;
+ dns_search_domain_unlink(first);
+
+ dns_search_domain_unlink_all(next);
+}
+
+void dns_search_domain_unlink_marked(DnsSearchDomain *first) {
+ DnsSearchDomain *next;
+
+ if (!first)
+ return;
+
+ next = first->domains_next;
+
+ if (first->marked)
+ dns_search_domain_unlink(first);
+
+ dns_search_domain_unlink_marked(next);
+}
+
+void dns_search_domain_mark_all(DnsSearchDomain *first) {
+ if (!first)
+ return;
+
+ first->marked = true;
+ dns_search_domain_mark_all(first->domains_next);
+}
+
+int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret) {
+ DnsSearchDomain *d;
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ LIST_FOREACH(domains, d, first) {
+
+ r = dns_name_equal(name, d->name);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ *ret = d;
+ return 1;
+ }
+ }
+
+ *ret = NULL;
+ return 0;
+}
diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h
new file mode 100644
index 0000000000..2e0af31dda
--- /dev/null
+++ b/src/resolve/resolved-dns-search-domain.h
@@ -0,0 +1,75 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+
+typedef struct DnsSearchDomain DnsSearchDomain;
+
+typedef enum DnsSearchDomainType {
+ DNS_SEARCH_DOMAIN_SYSTEM,
+ DNS_SEARCH_DOMAIN_LINK,
+} DnsSearchDomainType;
+
+#include "resolved-link.h"
+#include "resolved-manager.h"
+
+struct DnsSearchDomain {
+ Manager *manager;
+
+ unsigned n_ref;
+
+ DnsSearchDomainType type;
+ Link *link;
+
+ char *name;
+
+ bool marked:1;
+
+ bool linked:1;
+ LIST_FIELDS(DnsSearchDomain, domains);
+};
+
+int dns_search_domain_new(
+ Manager *m,
+ DnsSearchDomain **ret,
+ DnsSearchDomainType type,
+ Link *link,
+ const char *name);
+
+DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d);
+DnsSearchDomain* dns_search_domain_unref(DnsSearchDomain *d);
+
+void dns_search_domain_unlink(DnsSearchDomain *d);
+void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d);
+
+void dns_search_domain_unlink_all(DnsSearchDomain *first);
+void dns_search_domain_unlink_marked(DnsSearchDomain *first);
+void dns_search_domain_mark_all(DnsSearchDomain *first);
+
+int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret);
+
+static inline const char* DNS_SEARCH_DOMAIN_NAME(DnsSearchDomain *d) {
+ return d ? d->name : NULL;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsSearchDomain*, dns_search_domain_unref);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index e803f635ab..0ebd22fe22 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -21,7 +21,9 @@
#include "alloc-util.h"
#include "resolved-dns-server.h"
+#include "resolved-resolv-conf.h"
#include "siphash24.h"
+#include "string-util.h"
/* After how much time to repeat classic DNS requests */
#define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
@@ -35,36 +37,57 @@ int dns_server_new(
int family,
const union in_addr_union *in_addr) {
- DnsServer *s, *tail;
+ DnsServer *s;
assert(m);
assert((type == DNS_SERVER_LINK) == !!l);
assert(in_addr);
+ if (!IN_SET(family, AF_INET, AF_INET6))
+ return -EAFNOSUPPORT;
+
+ if (l) {
+ if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX)
+ return -E2BIG;
+ } else {
+ if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX)
+ return -E2BIG;
+ }
+
s = new0(DnsServer, 1);
if (!s)
return -ENOMEM;
s->n_ref = 1;
+ s->manager = m;
s->type = type;
s->family = family;
s->address = *in_addr;
s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
- if (type == DNS_SERVER_LINK) {
- LIST_FIND_TAIL(servers, l->dns_servers, tail);
- LIST_INSERT_AFTER(servers, l->dns_servers, tail, s);
+ switch (type) {
+
+ case DNS_SERVER_LINK:
s->link = l;
- } else if (type == DNS_SERVER_SYSTEM) {
- LIST_FIND_TAIL(servers, m->dns_servers, tail);
- LIST_INSERT_AFTER(servers, m->dns_servers, tail, s);
- } else if (type == DNS_SERVER_FALLBACK) {
- LIST_FIND_TAIL(servers, m->fallback_dns_servers, tail);
- LIST_INSERT_AFTER(servers, m->fallback_dns_servers, tail, s);
- } else
+ LIST_APPEND(servers, l->dns_servers, s);
+ l->n_dns_servers++;
+ break;
+
+ case DNS_SERVER_SYSTEM:
+ LIST_APPEND(servers, m->dns_servers, s);
+ m->n_dns_servers++;
+ break;
+
+ case DNS_SERVER_FALLBACK:
+ LIST_APPEND(servers, m->fallback_dns_servers, s);
+ m->n_dns_servers++;
+ break;
+
+ default:
assert_not_reached("Unknown server type");
+ }
- s->manager = m;
+ s->linked = true;
/* A new DNS server that isn't fallback is added and the one
* we used so far was a fallback one? Then let's try to pick
@@ -85,56 +108,127 @@ DnsServer* dns_server_ref(DnsServer *s) {
return NULL;
assert(s->n_ref > 0);
-
s->n_ref ++;
return s;
}
-static DnsServer* dns_server_free(DnsServer *s) {
+DnsServer* dns_server_unref(DnsServer *s) {
if (!s)
return NULL;
+ assert(s->n_ref > 0);
+ s->n_ref --;
+
+ if (s->n_ref > 0)
+ return NULL;
+
+ free(s);
+ return NULL;
+}
+
+void dns_server_unlink(DnsServer *s) {
+ assert(s);
+ assert(s->manager);
+
+ /* This removes the specified server from the linked list of
+ * servers, but any server might still stay around if it has
+ * refs, for example from an ongoing transaction. */
+
+ if (!s->linked)
+ return;
+
+ switch (s->type) {
+
+ case DNS_SERVER_LINK:
+ assert(s->link);
+ assert(s->link->n_dns_servers > 0);
+ LIST_REMOVE(servers, s->link->dns_servers, s);
+ break;
+
+ case DNS_SERVER_SYSTEM:
+ assert(s->manager->n_dns_servers > 0);
+ LIST_REMOVE(servers, s->manager->dns_servers, s);
+ s->manager->n_dns_servers--;
+ break;
+
+ case DNS_SERVER_FALLBACK:
+ assert(s->manager->n_dns_servers > 0);
+ LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
+ s->manager->n_dns_servers--;
+ break;
+ }
+
+ s->linked = false;
+
if (s->link && s->link->current_dns_server == s)
link_set_dns_server(s->link, NULL);
- if (s->manager && s->manager->current_dns_server == s)
+ if (s->manager->current_dns_server == s)
manager_set_dns_server(s->manager, NULL);
- free(s);
-
- return NULL;
+ dns_server_unref(s);
}
-DnsServer* dns_server_unref(DnsServer *s) {
- if (!s)
- return NULL;
+void dns_server_move_back_and_unmark(DnsServer *s) {
+ DnsServer *tail;
- assert(s->n_ref > 0);
+ assert(s);
- if (s->n_ref == 1)
- dns_server_free(s);
- else
- s->n_ref --;
+ if (!s->marked)
+ return;
- return NULL;
+ s->marked = false;
+
+ if (!s->linked || !s->servers_next)
+ return;
+
+ /* Move us to the end of the list, so that the order is
+ * strictly kept, if we are not at the end anyway. */
+
+ switch (s->type) {
+
+ case DNS_SERVER_LINK:
+ assert(s->link);
+ LIST_FIND_TAIL(servers, s, tail);
+ LIST_REMOVE(servers, s->link->dns_servers, s);
+ LIST_INSERT_AFTER(servers, s->link->dns_servers, tail, s);
+ break;
+
+ case DNS_SERVER_SYSTEM:
+ LIST_FIND_TAIL(servers, s, tail);
+ LIST_REMOVE(servers, s->manager->dns_servers, s);
+ LIST_INSERT_AFTER(servers, s->manager->dns_servers, tail, s);
+ break;
+
+ case DNS_SERVER_FALLBACK:
+ LIST_FIND_TAIL(servers, s, tail);
+ LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
+ LIST_INSERT_AFTER(servers, s->manager->fallback_dns_servers, tail, s);
+ break;
+
+ default:
+ assert_not_reached("Unknown server type");
+ }
}
void dns_server_packet_received(DnsServer *s, usec_t rtt) {
assert(s);
- if (rtt > s->max_rtt) {
- s->max_rtt = rtt;
- s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2),
- DNS_TIMEOUT_MAX_USEC);
- }
+ if (rtt <= s->max_rtt)
+ return;
+
+ s->max_rtt = rtt;
+ s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
}
void dns_server_packet_lost(DnsServer *s, usec_t usec) {
assert(s);
- if (s->resend_timeout <= usec)
- s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
+ if (s->resend_timeout > usec)
+ return;
+
+ s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
}
static void dns_server_hash_func(const void *p, struct siphash *state) {
@@ -161,3 +255,140 @@ const struct hash_ops dns_server_hash_ops = {
.hash = dns_server_hash_func,
.compare = dns_server_compare_func
};
+
+void dns_server_unlink_all(DnsServer *first) {
+ DnsServer *next;
+
+ if (!first)
+ return;
+
+ next = first->servers_next;
+ dns_server_unlink(first);
+
+ dns_server_unlink_all(next);
+}
+
+void dns_server_unlink_marked(DnsServer *first) {
+ DnsServer *next;
+
+ if (!first)
+ return;
+
+ next = first->servers_next;
+
+ if (first->marked)
+ dns_server_unlink(first);
+
+ dns_server_unlink_marked(next);
+}
+
+void dns_server_mark_all(DnsServer *first) {
+ if (!first)
+ return;
+
+ first->marked = true;
+ dns_server_mark_all(first->servers_next);
+}
+
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
+ DnsServer *s;
+
+ LIST_FOREACH(servers, s, first)
+ if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
+ return s;
+
+ return NULL;
+}
+
+DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
+ assert(m);
+
+ switch (t) {
+
+ case DNS_SERVER_SYSTEM:
+ return m->dns_servers;
+
+ case DNS_SERVER_FALLBACK:
+ return m->fallback_dns_servers;
+
+ default:
+ return NULL;
+ }
+}
+
+DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
+ assert(m);
+
+ if (m->current_dns_server == s)
+ return s;
+
+ if (s) {
+ _cleanup_free_ char *ip = NULL;
+
+ in_addr_to_string(s->family, &s->address, &ip);
+ log_info("Switching to system DNS server %s.", strna(ip));
+ }
+
+ dns_server_unref(m->current_dns_server);
+ m->current_dns_server = dns_server_ref(s);
+
+ if (m->unicast_scope)
+ dns_cache_flush(&m->unicast_scope->cache);
+
+ return s;
+}
+
+DnsServer *manager_get_dns_server(Manager *m) {
+ Link *l;
+ assert(m);
+
+ /* Try to read updates resolv.conf */
+ manager_read_resolv_conf(m);
+
+ /* If no DNS server was chose so far, pick the first one */
+ if (!m->current_dns_server)
+ manager_set_dns_server(m, m->dns_servers);
+
+ if (!m->current_dns_server) {
+ bool found = false;
+ Iterator i;
+
+ /* No DNS servers configured, let's see if there are
+ * any on any links. If not, we use the fallback
+ * servers */
+
+ HASHMAP_FOREACH(l, m->links, i)
+ if (l->dns_servers) {
+ found = true;
+ break;
+ }
+
+ if (!found)
+ manager_set_dns_server(m, m->fallback_dns_servers);
+ }
+
+ return m->current_dns_server;
+}
+
+void manager_next_dns_server(Manager *m) {
+ assert(m);
+
+ /* If there's currently no DNS server set, then the next
+ * manager_get_dns_server() will find one */
+ if (!m->current_dns_server)
+ return;
+
+ /* Change to the next one, but make sure to follow the linked
+ * list only if the server is still linked. */
+ if (m->current_dns_server->linked && m->current_dns_server->servers_next) {
+ manager_set_dns_server(m, m->current_dns_server->servers_next);
+ return;
+ }
+
+ /* If there was no next one, then start from the beginning of
+ * the list */
+ if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
+ manager_set_dns_server(m, m->fallback_dns_servers);
+ else
+ manager_set_dns_server(m, m->dns_servers);
+}
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 10111fd6bd..3a78d4a3b5 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -24,7 +24,6 @@
#include "in-addr-util.h"
typedef struct DnsServer DnsServer;
-typedef enum DnsServerSource DnsServerSource;
typedef enum DnsServerType {
DNS_SERVER_SYSTEM,
@@ -32,6 +31,7 @@ typedef enum DnsServerType {
DNS_SERVER_LINK,
} DnsServerType;
+#include "resolved-manager.h"
#include "resolved-link.h"
struct DnsServer {
@@ -40,7 +40,6 @@ struct DnsServer {
unsigned n_ref;
DnsServerType type;
-
Link *link;
int family;
@@ -51,23 +50,40 @@ struct DnsServer {
bool marked:1;
+ /* If linked is set, then this server appears in the servers linked list */
+ bool linked:1;
LIST_FIELDS(DnsServer, servers);
};
int dns_server_new(
Manager *m,
- DnsServer **s,
+ DnsServer **ret,
DnsServerType type,
- Link *l,
+ Link *link,
int family,
const union in_addr_union *address);
DnsServer* dns_server_ref(DnsServer *s);
DnsServer* dns_server_unref(DnsServer *s);
+void dns_server_unlink(DnsServer *s);
+void dns_server_move_back_and_unmark(DnsServer *s);
+
void dns_server_packet_received(DnsServer *s, usec_t rtt);
void dns_server_packet_lost(DnsServer *s, usec_t usec);
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr);
+
+void dns_server_unlink_all(DnsServer *first);
+void dns_server_unlink_marked(DnsServer *first);
+void dns_server_mark_all(DnsServer *first);
+
+DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t);
+
+DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
+DnsServer *manager_get_dns_server(Manager *m);
+void manager_next_dns_server(Manager *m);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
extern const struct hash_ops dns_server_hash_ops;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 6545f6cd8a..8c4f23a4da 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -29,7 +29,7 @@
#include "string-table.h"
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
- DnsQuery *q;
+ DnsQueryCandidate *c;
DnsZoneItem *i;
if (!t)
@@ -39,7 +39,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
dns_packet_unref(t->sent);
dns_packet_unref(t->received);
- dns_answer_unref(t->cached);
+
+ dns_answer_unref(t->answer);
sd_event_source_unref(t->dns_udp_event_source);
safe_close(t->dns_udp_fd);
@@ -48,7 +49,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
dns_stream_free(t->stream);
if (t->scope) {
- hashmap_remove(t->scope->transactions, t->key);
+ hashmap_remove_value(t->scope->transactions_by_key, t->key, t);
+ LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
if (t->id != 0)
hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
@@ -56,9 +58,10 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
dns_resource_key_unref(t->key);
- while ((q = set_steal_first(t->queries)))
- set_remove(q->transactions, t);
- set_free(t->queries);
+ while ((c = set_steal_first(t->query_candidates)))
+ set_remove(c->transactions, t);
+
+ set_free(t->query_candidates);
while ((i = set_steal_first(t->zone_items)))
i->probe_transaction = NULL;
@@ -76,7 +79,7 @@ void dns_transaction_gc(DnsTransaction *t) {
if (t->block_gc > 0)
return;
- if (set_isempty(t->queries) && set_isempty(t->zone_items))
+ if (set_isempty(t->query_candidates) && set_isempty(t->zone_items))
dns_transaction_free(t);
}
@@ -92,7 +95,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
if (r < 0)
return r;
- r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops);
+ r = hashmap_ensure_allocated(&s->transactions_by_key, &dns_resource_key_hash_ops);
if (r < 0)
return r;
@@ -101,6 +104,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
return -ENOMEM;
t->dns_udp_fd = -1;
+ t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID;
t->key = dns_resource_key_ref(key);
/* Find a fresh, unused transaction id */
@@ -115,12 +119,13 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
return r;
}
- r = hashmap_put(s->transactions, t->key, t);
+ r = hashmap_replace(s->transactions_by_key, t->key, t);
if (r < 0) {
hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id));
return r;
}
+ LIST_PREPEND(transactions_by_scope, s->transactions, t);
t->scope = s;
if (ret)
@@ -136,6 +141,9 @@ static void dns_transaction_stop(DnsTransaction *t) {
t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
t->stream = dns_stream_free(t->stream);
+
+ /* Note that we do not drop the UDP socket here, as we want to
+ * reuse it to repeat the interaction. */
}
static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
@@ -181,7 +189,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
}
void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
- DnsQuery *q;
+ DnsQueryCandidate *c;
DnsZoneItem *z;
Iterator i;
@@ -192,11 +200,12 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
* should hence not attempt to access the query or transaction
* after calling this function. */
- log_debug("Transaction on scope %s on %s/%s now complete with <%s>",
+ log_debug("Transaction on scope %s on %s/%s now complete with <%s> from %s",
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
- dns_transaction_state_to_string(state));
+ dns_transaction_state_to_string(state),
+ t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source));
t->state = state;
@@ -205,8 +214,8 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
/* Notify all queries that are interested, but make sure the
* transaction isn't freed while we are still looking at it */
t->block_gc++;
- SET_FOREACH(q, t->queries, i)
- dns_query_ready(q);
+ SET_FOREACH(c, t->query_candidates, i)
+ dns_query_candidate_ready(c);
SET_FOREACH(z, t->zone_items, i)
dns_zone_item_ready(z);
t->block_gc--;
@@ -314,6 +323,8 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
dns_server_unref(t->server);
t->server = dns_server_ref(server);
t->received = dns_packet_unref(t->received);
+ t->answer = dns_answer_unref(t->answer);
+ t->answer_rcode = 0;
t->stream->complete = on_stream_complete;
t->stream->transaction = t;
@@ -385,6 +396,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
t->received = dns_packet_ref(p);
}
+ t->answer_source = DNS_TRANSACTION_NETWORK;
+
if (p->ipproto == IPPROTO_TCP) {
if (DNS_PACKET_TC(p)) {
/* Truncated via TCP? Somebody must be fucking with us */
@@ -453,6 +466,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
return;
}
+ /* Install the answer as answer to the transaction */
+ dns_answer_unref(t->answer);
+ t->answer = dns_answer_ref(p->answer);
+ t->answer_rcode = DNS_PACKET_RCODE(p);
+
/* Only consider responses with equivalent query section to the request */
if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) {
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
@@ -460,7 +478,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
}
/* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
- dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
+ if (DNS_PACKET_SHALL_CACHE(p))
+ dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
@@ -623,8 +642,24 @@ int dns_transaction_go(DnsTransaction *t) {
t->n_attempts++;
t->start_usec = ts;
t->received = dns_packet_unref(t->received);
- t->cached = dns_answer_unref(t->cached);
- t->cached_rcode = 0;
+ t->answer = dns_answer_unref(t->answer);
+ t->answer_rcode = 0;
+ t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID;
+
+ /* Check the zone, but obly if this transaction is not used
+ * for probing or verifying a zone item. */
+ if (set_isempty(t->zone_items)) {
+
+ r = dns_zone_lookup(&t->scope->zone, t->key, &t->answer, NULL, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ t->answer_rcode = DNS_RCODE_SUCCESS;
+ t->answer_source = DNS_TRANSACTION_ZONE;
+ dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
+ return 0;
+ }
+ }
/* Check the cache, but only if this transaction is not used
* for probing or verifying a zone item. */
@@ -638,11 +673,12 @@ int dns_transaction_go(DnsTransaction *t) {
/* Let's then prune all outdated entries */
dns_cache_prune(&t->scope->cache);
- r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached);
+ r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer);
if (r < 0)
return r;
if (r > 0) {
- if (t->cached_rcode == DNS_RCODE_SUCCESS)
+ t->answer_source = DNS_TRANSACTION_CACHE;
+ if (t->answer_rcode == DNS_RCODE_SUCCESS)
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
else
dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
@@ -745,3 +781,10 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX]
[DNS_TRANSACTION_ABORTED] = "aborted",
};
DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);
+
+static const char* const dns_transaction_source_table[_DNS_TRANSACTION_SOURCE_MAX] = {
+ [DNS_TRANSACTION_NETWORK] = "network",
+ [DNS_TRANSACTION_CACHE] = "cache",
+ [DNS_TRANSACTION_ZONE] = "zone",
+};
+DEFINE_STRING_TABLE_LOOKUP(dns_transaction_source, DnsTransactionSource);
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index acf6a6f651..ee80dcf5a9 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -23,6 +23,7 @@
typedef struct DnsTransaction DnsTransaction;
typedef enum DnsTransactionState DnsTransactionState;
+typedef enum DnsTransactionSource DnsTransactionSource;
enum DnsTransactionState {
DNS_TRANSACTION_NULL,
@@ -39,10 +40,18 @@ enum DnsTransactionState {
_DNS_TRANSACTION_STATE_INVALID = -1
};
-#include "resolved-dns-scope.h"
+enum DnsTransactionSource {
+ DNS_TRANSACTION_NETWORK,
+ DNS_TRANSACTION_CACHE,
+ DNS_TRANSACTION_ZONE,
+ _DNS_TRANSACTION_SOURCE_MAX,
+ _DNS_TRANSACTION_SOURCE_INVALID = -1
+};
+
+#include "resolved-dns-answer.h"
#include "resolved-dns-packet.h"
#include "resolved-dns-question.h"
-#include "resolved-dns-answer.h"
+#include "resolved-dns-scope.h"
struct DnsTransaction {
DnsScope *scope;
@@ -55,8 +64,10 @@ struct DnsTransaction {
bool initial_jitter;
DnsPacket *sent, *received;
- DnsAnswer *cached;
- int cached_rcode;
+
+ DnsAnswer *answer;
+ int answer_rcode;
+ DnsTransactionSource answer_source;
usec_t start_usec;
sd_event_source *timeout_event_source;
@@ -71,9 +82,10 @@ struct DnsTransaction {
/* TCP connection logic, if we need it */
DnsStream *stream;
- /* Queries this transaction is referenced by and that shall be
- * notified about this specific transaction completing. */
- Set *queries;
+ /* Query candidates this transaction is referenced by and that
+ * shall be notified about this specific transaction
+ * completing. */
+ Set *query_candidates;
/* Zone items this transaction is referenced by and that shall
* be notified about completion. */
@@ -96,6 +108,9 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state);
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
+const char* dns_transaction_source_to_string(DnsTransactionSource p) _const_;
+DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
+
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
@@ -105,4 +120,4 @@ DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
-#define TRANSACTION_ATTEMPTS_MAX(p) (p == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX)
+#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX)
diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c
index 48dcf76daa..493d11dd14 100644
--- a/src/resolve/resolved-dns-zone.c
+++ b/src/resolve/resolved-dns-zone.c
@@ -283,97 +283,76 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) {
return 0;
}
-int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
+int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
- unsigned i, n_answer = 0, n_soa = 0;
- bool tentative = true;
+ unsigned n_answer = 0;
+ DnsZoneItem *j, *first;
+ bool tentative = true, need_soa = false;
int r;
assert(z);
- assert(q);
+ assert(key);
assert(ret_answer);
- assert(ret_soa);
- if (q->n_keys <= 0) {
- *ret_answer = NULL;
- *ret_soa = NULL;
-
- if (ret_tentative)
- *ret_tentative = false;
+ /* First iteration, count what we have */
- return 0;
- }
+ if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
+ bool found = false, added = false;
+ int k;
- /* First iteration, count what we have */
- for (i = 0; i < q->n_keys; i++) {
- DnsZoneItem *j, *first;
+ /* If this is a generic match, then we have to
+ * go through the list by the name and look
+ * for everything manually */
- if (q->keys[i]->type == DNS_TYPE_ANY ||
- q->keys[i]->class == DNS_CLASS_ANY) {
- bool found = false, added = false;
- int k;
+ first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ LIST_FOREACH(by_name, j, first) {
+ if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
+ continue;
- /* If this is a generic match, then we have to
- * go through the list by the name and look
- * for everything manually */
+ found = true;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i]));
- LIST_FOREACH(by_name, j, first) {
- if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
- continue;
+ k = dns_resource_key_match_rr(key, j->rr, NULL);
+ if (k < 0)
+ return k;
+ if (k > 0) {
+ n_answer++;
+ added = true;
+ }
- found = true;
+ }
- k = dns_resource_key_match_rr(q->keys[i], j->rr);
- if (k < 0)
- return k;
- if (k > 0) {
- n_answer++;
- added = true;
- }
+ if (found && !added)
+ need_soa = true;
- }
+ } else {
+ bool found = false;
- if (found && !added)
- n_soa++;
+ /* If this is a specific match, then look for
+ * the right key immediately */
- } else {
- bool found = false;
+ first = hashmap_get(z->by_key, key);
+ LIST_FOREACH(by_key, j, first) {
+ if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
+ continue;
- /* If this is a specific match, then look for
- * the right key immediately */
+ found = true;
+ n_answer++;
+ }
- first = hashmap_get(z->by_key, q->keys[i]);
- LIST_FOREACH(by_key, j, first) {
+ if (!found) {
+ first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
- found = true;
- n_answer++;
- }
-
- if (!found) {
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i]));
- LIST_FOREACH(by_name, j, first) {
- if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
- continue;
-
- n_soa++;
- break;
- }
+ need_soa = true;
+ break;
}
}
}
- if (n_answer <= 0 && n_soa <= 0) {
- *ret_answer = NULL;
- *ret_soa = NULL;
-
- if (ret_tentative)
- *ret_tentative = false;
-
- return 0;
- }
+ if (n_answer <= 0 && !need_soa)
+ goto return_empty;
if (n_answer > 0) {
answer = dns_answer_new(n_answer);
@@ -381,99 +360,113 @@ int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswe
return -ENOMEM;
}
- if (n_soa > 0) {
- soa = dns_answer_new(n_soa);
+ if (need_soa) {
+ soa = dns_answer_new(1);
if (!soa)
return -ENOMEM;
}
/* Second iteration, actually add the RRs to the answers */
- for (i = 0; i < q->n_keys; i++) {
- DnsZoneItem *j, *first;
-
- if (q->keys[i]->type == DNS_TYPE_ANY ||
- q->keys[i]->class == DNS_CLASS_ANY) {
- bool found = false, added = false;
- int k;
+ if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
+ bool found = false, added = false;
+ int k;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i]));
- LIST_FOREACH(by_name, j, first) {
- if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
- continue;
-
- found = true;
+ first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ LIST_FOREACH(by_name, j, first) {
+ if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
+ continue;
- if (j->state != DNS_ZONE_ITEM_PROBING)
- tentative = false;
+ found = true;
- k = dns_resource_key_match_rr(q->keys[i], j->rr);
- if (k < 0)
- return k;
- if (k > 0) {
- r = dns_answer_add(answer, j->rr, 0);
- if (r < 0)
- return r;
+ if (j->state != DNS_ZONE_ITEM_PROBING)
+ tentative = false;
- added = true;
- }
- }
-
- if (found && !added) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL);
+ k = dns_resource_key_match_rr(key, j->rr, NULL);
+ if (k < 0)
+ return k;
+ if (k > 0) {
+ r = dns_answer_add(answer, j->rr, 0);
if (r < 0)
return r;
+
+ added = true;
}
- } else {
- bool found = false;
+ }
- first = hashmap_get(z->by_key, q->keys[i]);
- LIST_FOREACH(by_key, j, first) {
- if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
- continue;
+ if (found && !added) {
+ r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ if (r < 0)
+ return r;
+ }
+ } else {
+ bool found = false;
- found = true;
+ first = hashmap_get(z->by_key, key);
+ LIST_FOREACH(by_key, j, first) {
+ if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
+ continue;
- if (j->state != DNS_ZONE_ITEM_PROBING)
- tentative = false;
+ found = true;
- r = dns_answer_add(answer, j->rr, 0);
- if (r < 0)
- return r;
- }
+ if (j->state != DNS_ZONE_ITEM_PROBING)
+ tentative = false;
+
+ r = dns_answer_add(answer, j->rr, 0);
+ if (r < 0)
+ return r;
+ }
- if (!found) {
- bool add_soa = false;
+ if (!found) {
+ bool add_soa = false;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i]));
- LIST_FOREACH(by_name, j, first) {
- if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
- continue;
+ first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ LIST_FOREACH(by_name, j, first) {
+ if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
+ continue;
- if (j->state != DNS_ZONE_ITEM_PROBING)
- tentative = false;
+ if (j->state != DNS_ZONE_ITEM_PROBING)
+ tentative = false;
- add_soa = true;
- }
+ add_soa = true;
+ }
- if (add_soa) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL);
- if (r < 0)
- return r;
- }
+ if (add_soa) {
+ r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ if (r < 0)
+ return r;
}
}
}
+ /* If the caller sets ret_tentative to NULL, then use this as
+ * indication to not return tentative entries */
+
+ if (!ret_tentative && tentative)
+ goto return_empty;
+
*ret_answer = answer;
answer = NULL;
- *ret_soa = soa;
- soa = NULL;
+ if (ret_soa) {
+ *ret_soa = soa;
+ soa = NULL;
+ }
if (ret_tentative)
*ret_tentative = tentative;
return 1;
+
+return_empty:
+ *ret_answer = NULL;
+
+ if (ret_soa)
+ *ret_soa = NULL;
+
+ if (ret_tentative)
+ *ret_tentative = false;
+
+ return 0;
}
void dns_zone_item_conflict(DnsZoneItem *i) {
diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h
index 495d17cdb1..44a8624c30 100644
--- a/src/resolve/resolved-dns-zone.h
+++ b/src/resolve/resolved-dns-zone.h
@@ -31,9 +31,9 @@ typedef struct DnsZone {
typedef struct DnsZoneItem DnsZoneItem;
typedef enum DnsZoneItemState DnsZoneItemState;
-#include "resolved-dns-rr.h"
-#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
+#include "resolved-dns-question.h"
+#include "resolved-dns-rr.h"
#include "resolved-dns-transaction.h"
/* RFC 4795 Section 2.8. suggests a TTL of 30s by default */
@@ -67,7 +67,7 @@ void dns_zone_flush(DnsZone *z);
int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe);
void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr);
-int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **answer, DnsAnswer **soa, bool *tentative);
+int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **answer, DnsAnswer **soa, bool *tentative);
void dns_zone_item_conflict(DnsZoneItem *i);
void dns_zone_item_ready(DnsZoneItem *i);
diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf
index 8e78fbf06a..50662656d5 100644
--- a/src/resolve/resolved-gperf.gperf
+++ b/src/resolve/resolved-gperf.gperf
@@ -14,6 +14,7 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Resolve.DNS, config_parse_dnsv, DNS_SERVER_SYSTEM, 0
-Resolve.FallbackDNS, config_parse_dnsv, DNS_SERVER_FALLBACK, 0
-Resolve.LLMNR, config_parse_support, 0, offsetof(Manager, llmnr_support)
+Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
+Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
+Resolve.Domains, config_parse_search_domains, 0, 0
+Resolve.LLMNR, config_parse_support, 0, offsetof(Manager, llmnr_support)
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 2892641075..ddd9427dab 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -65,19 +65,15 @@ Link *link_free(Link *l) {
if (!l)
return NULL;
+ dns_server_unlink_marked(l->dns_servers);
+ dns_search_domain_unlink_all(l->search_domains);
+
while (l->addresses)
link_address_free(l->addresses);
if (l->manager)
hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
- while (l->dns_servers) {
- DnsServer *s = l->dns_servers;
-
- LIST_REMOVE(servers, l->dns_servers, s);
- dns_server_unref(s);
- }
-
dns_scope_free(l->unicast_scope);
dns_scope_free(l->llmnr_ipv4_scope);
dns_scope_free(l->llmnr_ipv6_scope);
@@ -158,7 +154,6 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) {
static int link_update_dns_servers(Link *l) {
_cleanup_strv_free_ char **nameservers = NULL;
char **nameserver;
- DnsServer *s, *nx;
int r;
assert(l);
@@ -167,20 +162,20 @@ static int link_update_dns_servers(Link *l) {
if (r < 0)
goto clear;
- LIST_FOREACH(servers, s, l->dns_servers)
- s->marked = true;
+ dns_server_mark_all(l->dns_servers);
STRV_FOREACH(nameserver, nameservers) {
union in_addr_union a;
+ DnsServer *s;
int family;
r = in_addr_from_string_auto(*nameserver, &family, &a);
if (r < 0)
goto clear;
- s = link_find_dns_server(l, family, &a);
+ s = dns_server_find(l->dns_servers, family, &a);
if (s)
- s->marked = false;
+ dns_server_move_back_and_unmark(s);
else {
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
if (r < 0)
@@ -188,22 +183,11 @@ static int link_update_dns_servers(Link *l) {
}
}
- LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
- if (s->marked) {
- LIST_REMOVE(servers, l->dns_servers, s);
- dns_server_unref(s);
- }
-
+ dns_server_unlink_marked(l->dns_servers);
return 0;
clear:
- while (l->dns_servers) {
- s = l->dns_servers;
-
- LIST_REMOVE(servers, l->dns_servers, s);
- dns_server_unref(s);
- }
-
+ dns_server_unlink_all(l->dns_servers);
return r;
}
@@ -236,29 +220,56 @@ clear:
return r;
}
-static int link_update_domains(Link *l) {
+static int link_update_search_domains(Link *l) {
+ _cleanup_strv_free_ char **domains = NULL;
+ char **i;
int r;
- if (!l->unicast_scope)
- return 0;
-
- l->unicast_scope->domains = strv_free(l->unicast_scope->domains);
+ assert(l);
- r = sd_network_link_get_domains(l->ifindex,
- &l->unicast_scope->domains);
+ r = sd_network_link_get_domains(l->ifindex, &domains);
if (r < 0)
- return r;
+ goto clear;
+
+ dns_search_domain_mark_all(l->search_domains);
+
+ STRV_FOREACH(i, domains) {
+ DnsSearchDomain *d;
+
+ r = dns_search_domain_find(l->search_domains, *i, &d);
+ if (r < 0)
+ goto clear;
+
+ if (r > 0)
+ dns_search_domain_move_back_and_unmark(d);
+ else {
+ r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
+ if (r < 0)
+ goto clear;
+ }
+ }
+ dns_search_domain_unlink_marked(l->search_domains);
return 0;
+
+clear:
+ dns_search_domain_unlink_all(l->search_domains);
+ return r;
}
int link_update_monitor(Link *l) {
+ int r;
+
assert(l);
link_update_dns_servers(l);
link_update_llmnr_support(l);
link_allocate_scopes(l);
- link_update_domains(l);
+
+ r = link_update_search_domains(l);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
+
link_add_rrs(l, false);
return 0;
@@ -303,17 +314,6 @@ LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *i
return NULL;
}
-DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
- DnsServer *s;
-
- assert(l);
-
- LIST_FOREACH(servers, s, l->dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr))
- return s;
- return NULL;
-}
-
DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
assert(l);
@@ -327,7 +327,8 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
}
- l->current_dns_server = s;
+ dns_server_unref(l->current_dns_server);
+ l->current_dns_server = dns_server_ref(s);
if (l->unicast_scope)
dns_cache_flush(&l->unicast_scope->cache);
@@ -350,7 +351,9 @@ void link_next_dns_server(Link *l) {
if (!l->current_dns_server)
return;
- if (l->current_dns_server->servers_next) {
+ /* Change to the next one, but make sure to follow the linked
+ * list only if this server is actually still linked. */
+ if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
link_set_dns_server(l, l->current_dns_server->servers_next);
return;
}
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index e3ab27c249..eb00015bd5 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -30,8 +30,13 @@ typedef struct Link Link;
typedef struct LinkAddress LinkAddress;
#include "resolved-dns-rr.h"
+#include "resolved-dns-search-domain.h"
+#include "resolved-dns-server.h"
#include "resolved-manager.h"
+#define LINK_SEARCH_DOMAINS_MAX 32
+#define LINK_DNS_SERVERS_MAX 32
+
struct LinkAddress {
Link *link;
@@ -56,6 +61,10 @@ struct Link {
LIST_HEAD(DnsServer, dns_servers);
DnsServer *current_dns_server;
+ unsigned n_dns_servers;
+
+ LIST_HEAD(DnsSearchDomain, search_domains);
+ unsigned n_search_domains;
Support llmnr_support;
@@ -76,7 +85,6 @@ LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *i
void link_add_rrs(Link *l, bool force_remove);
DnsServer* link_set_dns_server(Link *l, DnsServer *s);
-DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr);
DnsServer* link_get_dns_server(Link *l);
void link_next_dns_server(Link *l);
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index 5c3a4a00c3..6a7ff9d245 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <resolv.h>
#include <netinet/in.h>
+#include <resolv.h>
#include "fd-util.h"
#include "resolved-llmnr.h"
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index a588538b52..f1f454c786 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -21,7 +21,6 @@
#include <netinet/in.h>
#include <poll.h>
-#include <resolv.h>
#include <sys/ioctl.h>
#include "af-list.h"
@@ -40,6 +39,7 @@
#include "resolved-conf.h"
#include "resolved-llmnr.h"
#include "resolved-manager.h"
+#include "resolved-resolv-conf.h"
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
@@ -351,7 +351,7 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
return -EINVAL;
}
- r = dns_label_escape(label, r, &n);
+ r = dns_label_escape_new(label, r, &n);
if (r < 0)
return log_error_errno(r, "Failed to escape host name: %m");
@@ -476,10 +476,7 @@ int manager_new(Manager **ret) {
m->llmnr_support = SUPPORT_YES;
m->read_resolv_conf = true;
-
- r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
- if (r < 0)
- return r;
+ m->need_builtin_fallbacks = true;
r = sd_event_default(&m->event);
if (r < 0)
@@ -536,15 +533,16 @@ Manager *manager_free(Manager *m) {
if (!m)
return NULL;
+ dns_server_unlink_all(m->dns_servers);
+ dns_server_unlink_all(m->fallback_dns_servers);
+ dns_search_domain_unlink_all(m->search_domains);
+
while ((l = hashmap_first(m->links)))
link_free(l);
while (m->dns_queries)
dns_query_free(m->dns_queries);
- manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
- manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
-
dns_scope_free(m->unicast_scope);
hashmap_free(m->links);
@@ -553,6 +551,9 @@ Manager *manager_free(Manager *m) {
sd_event_source_unref(m->network_event_source);
sd_network_monitor_unref(m->network_monitor);
+ sd_netlink_unref(m->rtnl);
+ sd_event_source_unref(m->rtnl_event_source);
+
manager_llmnr_stop(m);
sd_bus_slot_unref(m->prepare_for_sleep_slot);
@@ -576,294 +577,6 @@ Manager *manager_free(Manager *m) {
return NULL;
}
-int manager_read_resolv_conf(Manager *m) {
- _cleanup_fclose_ FILE *f = NULL;
- struct stat st, own;
- char line[LINE_MAX];
- DnsServer *s, *nx;
- usec_t t;
- int r;
-
- assert(m);
-
- /* Reads the system /etc/resolv.conf, if it exists and is not
- * symlinked to our own resolv.conf instance */
-
- if (!m->read_resolv_conf)
- return 0;
-
- r = stat("/etc/resolv.conf", &st);
- if (r < 0) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
- r = -errno;
- goto clear;
- }
-
- /* Have we already seen the file? */
- t = timespec_load(&st.st_mtim);
- if (t == m->resolv_conf_mtime)
- return 0;
-
- m->resolv_conf_mtime = t;
-
- /* Is it symlinked to our own file? */
- if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
- st.st_dev == own.st_dev &&
- st.st_ino == own.st_ino) {
- r = 0;
- goto clear;
- }
-
- f = fopen("/etc/resolv.conf", "re");
- if (!f) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
- r = -errno;
- goto clear;
- }
-
- if (fstat(fileno(f), &st) < 0) {
- r = log_error_errno(errno, "Failed to stat open file: %m");
- goto clear;
- }
-
- LIST_FOREACH(servers, s, m->dns_servers)
- s->marked = true;
-
- FOREACH_LINE(line, f, r = -errno; goto clear) {
- union in_addr_union address;
- int family;
- char *l;
- const char *a;
-
- truncate_nl(line);
-
- l = strstrip(line);
- if (*l == '#' || *l == ';')
- continue;
-
- a = first_word(l, "nameserver");
- if (!a)
- continue;
-
- r = in_addr_from_string_auto(a, &family, &address);
- if (r < 0) {
- log_warning("Failed to parse name server %s.", a);
- continue;
- }
-
- LIST_FOREACH(servers, s, m->dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
- break;
-
- if (s)
- s->marked = false;
- else {
- r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
- if (r < 0)
- goto clear;
- }
- }
-
- LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
- if (s->marked) {
- LIST_REMOVE(servers, m->dns_servers, s);
- dns_server_unref(s);
- }
-
- /* Whenever /etc/resolv.conf changes, start using the first
- * DNS server of it. This is useful to deal with broken
- * network managing implementations (like NetworkManager),
- * that when connecting to a VPN place both the VPN DNS
- * servers and the local ones in /etc/resolv.conf. Without
- * resetting the DNS server to use back to the first entry we
- * will continue to use the local one thus being unable to
- * resolve VPN domains. */
- manager_set_dns_server(m, m->dns_servers);
-
- return 0;
-
-clear:
- while (m->dns_servers) {
- s = m->dns_servers;
-
- LIST_REMOVE(servers, m->dns_servers, s);
- dns_server_unref(s);
- }
-
- return r;
-}
-
-static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(s);
- assert(f);
- assert(count);
-
- r = in_addr_to_string(s->family, &s->address, &t);
- if (r < 0) {
- log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
- return;
- }
-
- if (*count == MAXNS)
- fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
-
- fprintf(f, "nameserver %s\n", t);
- (*count) ++;
-}
-
-static void write_resolv_conf_search(
- const char *domain, FILE *f,
- unsigned *count,
- unsigned *length) {
-
- assert(domain);
- assert(f);
- assert(length);
-
- if (*count >= MAXDNSRCH ||
- *length + strlen(domain) > 256) {
- if (*count == MAXDNSRCH)
- fputs(" # Too many search domains configured, remaining ones ignored.", f);
- if (*length <= 256)
- fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
-
- return;
- }
-
- fprintf(f, " %s", domain);
-
- (*length) += strlen(domain);
- (*count) ++;
-}
-
-static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
- Iterator i;
-
- fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
- "# Third party programs must not access this file directly, but\n"
- "# only through the symlink at /etc/resolv.conf. To manage\n"
- "# resolv.conf(5) in a different way, replace the symlink by a\n"
- "# static file or a different symlink.\n\n", f);
-
- if (ordered_set_isempty(dns))
- fputs("# No DNS servers known.\n", f);
- else {
- DnsServer *s;
- unsigned count = 0;
-
- ORDERED_SET_FOREACH(s, dns, i)
- write_resolv_conf_server(s, f, &count);
- }
-
- if (!ordered_set_isempty(domains)) {
- unsigned length = 0, count = 0;
- char *domain;
-
- fputs("search", f);
- ORDERED_SET_FOREACH(domain, domains, i)
- write_resolv_conf_search(domain, f, &count, &length);
- fputs("\n", f);
- }
-
- return fflush_and_check(f);
-}
-
-int manager_write_resolv_conf(Manager *m) {
- static const char path[] = "/run/systemd/resolve/resolv.conf";
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
- DnsServer *s;
- Iterator i;
- Link *l;
- int r;
-
- assert(m);
-
- /* Read the system /etc/resolv.conf first */
- manager_read_resolv_conf(m);
-
- /* Add the full list to a set, to filter out duplicates */
- dns = ordered_set_new(&dns_server_hash_ops);
- if (!dns)
- return -ENOMEM;
-
- domains = ordered_set_new(&dns_name_hash_ops);
- if (!domains)
- return -ENOMEM;
-
- /* First add the system-wide servers */
- LIST_FOREACH(servers, s, m->dns_servers) {
- r = ordered_set_put(dns, s);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return r;
- }
-
- /* Then, add the per-link servers and domains */
- HASHMAP_FOREACH(l, m->links, i) {
- char **domain;
-
- LIST_FOREACH(servers, s, l->dns_servers) {
- r = ordered_set_put(dns, s);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return r;
- }
-
- if (!l->unicast_scope)
- continue;
-
- STRV_FOREACH(domain, l->unicast_scope->domains) {
- r = ordered_set_put(domains, *domain);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return r;
- }
- }
-
- /* If we found nothing, add the fallback servers */
- if (ordered_set_isempty(dns)) {
- LIST_FOREACH(servers, s, m->fallback_dns_servers) {
- r = ordered_set_put(dns, s);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return r;
- }
- }
-
- r = fopen_temporary_label(path, path, &f, &temp_path);
- if (r < 0)
- return r;
-
- fchmod(fileno(f), 0644);
-
- r = write_resolv_conf_contents(f, dns, domains);
- if (r < 0)
- goto fail;
-
- if (rename(temp_path, path) < 0) {
- r = -errno;
- goto fail;
- }
-
- return 0;
-
-fail:
- (void) unlink(path);
- (void) unlink(temp_path);
- return r;
-}
-
int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
union {
@@ -1171,97 +884,6 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add
return -EAFNOSUPPORT;
}
-DnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
- DnsServer *s;
-
- assert(m);
- assert(in_addr);
-
- LIST_FOREACH(servers, s, m->dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
- return s;
-
- LIST_FOREACH(servers, s, m->fallback_dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
- return s;
-
- return NULL;
-}
-
-DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
- assert(m);
-
- if (m->current_dns_server == s)
- return s;
-
- if (s) {
- _cleanup_free_ char *ip = NULL;
-
- in_addr_to_string(s->family, &s->address, &ip);
- log_info("Switching to system DNS server %s.", strna(ip));
- }
-
- m->current_dns_server = s;
-
- if (m->unicast_scope)
- dns_cache_flush(&m->unicast_scope->cache);
-
- return s;
-}
-
-DnsServer *manager_get_dns_server(Manager *m) {
- Link *l;
- assert(m);
-
- /* Try to read updates resolv.conf */
- manager_read_resolv_conf(m);
-
- if (!m->current_dns_server)
- manager_set_dns_server(m, m->dns_servers);
-
- if (!m->current_dns_server) {
- bool found = false;
- Iterator i;
-
- /* No DNS servers configured, let's see if there are
- * any on any links. If not, we use the fallback
- * servers */
-
- HASHMAP_FOREACH(l, m->links, i)
- if (l->dns_servers) {
- found = true;
- break;
- }
-
- if (!found)
- manager_set_dns_server(m, m->fallback_dns_servers);
- }
-
- return m->current_dns_server;
-}
-
-void manager_next_dns_server(Manager *m) {
- assert(m);
-
- /* If there's currently no DNS server set, then the next
- * manager_get_dns_server() will find one */
- if (!m->current_dns_server)
- return;
-
- /* Change to the next one */
- if (m->current_dns_server->servers_next) {
- manager_set_dns_server(m, m->current_dns_server->servers_next);
- return;
- }
-
- /* If there was no next one, then start from the beginning of
- * the list */
- if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
- manager_set_dns_server(m, m->fallback_dns_servers);
- else
- manager_set_dns_server(m, m->dns_servers);
-}
-
uint32_t manager_find_mtu(Manager *m) {
uint32_t mtu = 0;
Link *l;
@@ -1415,42 +1037,102 @@ void manager_verify_all(Manager *m) {
dns_zone_verify_all(&s->zone);
}
-void manager_flush_dns_servers(Manager *m, DnsServerType t) {
+int manager_is_own_hostname(Manager *m, const char *name) {
+ int r;
+
+ assert(m);
+ assert(name);
+
+ if (m->llmnr_hostname) {
+ r = dns_name_equal(name, m->llmnr_hostname);
+ if (r != 0)
+ return r;
+ }
+
+ if (m->mdns_hostname)
+ return dns_name_equal(name, m->mdns_hostname);
+
+ return 0;
+}
+
+int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
DnsServer *s;
+ Iterator i;
+ Link *l;
+ int r;
assert(m);
+ assert(dns);
+
+ r = ordered_set_ensure_allocated(dns, &dns_server_hash_ops);
+ if (r < 0)
+ return r;
- if (t == DNS_SERVER_SYSTEM)
- while (m->dns_servers) {
- s = m->dns_servers;
+ /* First add the system-wide servers and domains */
+ LIST_FOREACH(servers, s, m->dns_servers) {
+ r = ordered_set_put(*dns, s);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return r;
+ }
- LIST_REMOVE(servers, m->dns_servers, s);
- dns_server_unref(s);
+ /* Then, add the per-link servers */
+ HASHMAP_FOREACH(l, m->links, i) {
+ LIST_FOREACH(servers, s, l->dns_servers) {
+ r = ordered_set_put(*dns, s);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return r;
}
+ }
- if (t == DNS_SERVER_FALLBACK)
- while (m->fallback_dns_servers) {
- s = m->fallback_dns_servers;
-
- LIST_REMOVE(servers, m->fallback_dns_servers, s);
- dns_server_unref(s);
+ /* If we found nothing, add the fallback servers */
+ if (ordered_set_isempty(*dns)) {
+ LIST_FOREACH(servers, s, m->fallback_dns_servers) {
+ r = ordered_set_put(*dns, s);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return r;
}
+ }
+
+ return 0;
}
-int manager_is_own_hostname(Manager *m, const char *name) {
+int manager_compile_search_domains(Manager *m, OrderedSet **domains) {
+ DnsSearchDomain *d;
+ Iterator i;
+ Link *l;
int r;
assert(m);
- assert(name);
+ assert(domains);
- if (m->llmnr_hostname) {
- r = dns_name_equal(name, m->llmnr_hostname);
- if (r != 0)
+ r = ordered_set_ensure_allocated(domains, &dns_name_hash_ops);
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(domains, d, m->search_domains) {
+ r = ordered_set_put(*domains, d->name);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
return r;
}
- if (m->mdns_hostname)
- return dns_name_equal(name, m->mdns_hostname);
+ HASHMAP_FOREACH(l, m->links, i) {
+
+ LIST_FOREACH(domains, d, l->search_domains) {
+ r = ordered_set_put(*domains, d->name);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return r;
+ }
+ }
return 0;
}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index fe7fe99505..d00c444583 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -22,10 +22,12 @@
***/
#include "sd-event.h"
-#include "sd-network.h"
#include "sd-netlink.h"
-#include "list.h"
+#include "sd-network.h"
+
#include "hashmap.h"
+#include "list.h"
+#include "ordered-set.h"
typedef struct Manager Manager;
typedef enum Support Support;
@@ -39,9 +41,14 @@ enum Support {
};
#include "resolved-dns-query.h"
+#include "resolved-dns-search-domain.h"
+#include "resolved-dns-server.h"
#include "resolved-dns-stream.h"
#include "resolved-link.h"
+#define MANAGER_SEARCH_DOMAINS_MAX 32
+#define MANAGER_DNS_SERVERS_MAX 32
+
struct Manager {
sd_event *event;
@@ -67,9 +74,15 @@ struct Manager {
/* Unicast dns */
LIST_HEAD(DnsServer, dns_servers);
LIST_HEAD(DnsServer, fallback_dns_servers);
+ unsigned n_dns_servers; /* counts both main and fallback */
DnsServer *current_dns_server;
- bool read_resolv_conf;
+ LIST_HEAD(DnsSearchDomain, search_domains);
+ unsigned n_search_domains;
+
+ bool need_builtin_fallbacks:1;
+
+ bool read_resolv_conf:1;
usec_t resolv_conf_mtime;
LIST_HEAD(DnsScope, dns_scopes);
@@ -112,13 +125,6 @@ int manager_new(Manager **ret);
Manager* manager_free(Manager *m);
int manager_start(Manager *m);
-int manager_read_resolv_conf(Manager *m);
-int manager_write_resolv_conf(Manager *m);
-
-DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
-DnsServer *manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr);
-DnsServer *manager_get_dns_server(Manager *m);
-void manager_next_dns_server(Manager *m);
uint32_t manager_find_mtu(Manager *m);
@@ -137,13 +143,14 @@ DnsScope* manager_find_scope(Manager *m, DnsPacket *p);
void manager_verify_all(Manager *m);
-void manager_flush_dns_servers(Manager *m, DnsServerType t);
-
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
#define EXTRA_CMSG_SPACE 1024
int manager_is_own_hostname(Manager *m, const char *name);
+int manager_compile_dns_servers(Manager *m, OrderedSet **servers);
+int manager_compile_search_domains(Manager *m, OrderedSet **domains);
+
const char* support_to_string(Support p) _const_;
int support_from_string(const char *s) _pure_;
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
new file mode 100644
index 0000000000..956f380f3c
--- /dev/null
+++ b/src/resolve/resolved-resolv-conf.c
@@ -0,0 +1,273 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <resolv.h>
+
+#include "alloc-util.h"
+#include "dns-domain.h"
+#include "fd-util.h"
+#include "fileio-label.h"
+#include "fileio.h"
+#include "ordered-set.h"
+#include "resolved-conf.h"
+#include "resolved-resolv-conf.h"
+#include "string-util.h"
+#include "strv.h"
+
+int manager_read_resolv_conf(Manager *m) {
+ _cleanup_fclose_ FILE *f = NULL;
+ struct stat st, own;
+ char line[LINE_MAX];
+ usec_t t;
+ int r;
+
+ assert(m);
+
+ /* Reads the system /etc/resolv.conf, if it exists and is not
+ * symlinked to our own resolv.conf instance */
+
+ if (!m->read_resolv_conf)
+ return 0;
+
+ r = stat("/etc/resolv.conf", &st);
+ if (r < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ r = log_warning_errno(errno, "Failed to stat /etc/resolv.conf: %m");
+ goto clear;
+ }
+
+ /* Have we already seen the file? */
+ t = timespec_load(&st.st_mtim);
+ if (t == m->resolv_conf_mtime)
+ return 0;
+
+ /* Is it symlinked to our own file? */
+ if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
+ st.st_dev == own.st_dev &&
+ st.st_ino == own.st_ino)
+ return 0;
+
+ f = fopen("/etc/resolv.conf", "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
+
+ r = log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
+ goto clear;
+ }
+
+ if (fstat(fileno(f), &st) < 0) {
+ r = log_error_errno(errno, "Failed to stat open file: %m");
+ goto clear;
+ }
+
+ dns_server_mark_all(m->dns_servers);
+ dns_search_domain_mark_all(m->search_domains);
+
+ FOREACH_LINE(line, f, r = -errno; goto clear) {
+ const char *a;
+ char *l;
+
+ l = strstrip(line);
+ if (*l == '#' || *l == ';')
+ continue;
+
+ a = first_word(l, "nameserver");
+ if (a) {
+ r = manager_add_dns_server_by_string(m, DNS_SERVER_SYSTEM, a);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
+
+ continue;
+ }
+
+ a = first_word(l, "domain");
+ if (!a) /* We treat "domain" lines, and "search" lines as equivalent, and add both to our list. */
+ a = first_word(l, "search");
+ if (a) {
+ r = manager_parse_search_domains_and_warn(m, a);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse search domain string '%s', ignoring.", a);
+ }
+ }
+
+ m->resolv_conf_mtime = t;
+
+ /* Flush out all servers and search domains that are still
+ * marked. Those are then ones that didn't appear in the new
+ * /etc/resolv.conf */
+ dns_server_unlink_marked(m->dns_servers);
+ dns_search_domain_unlink_marked(m->search_domains);
+
+ /* Whenever /etc/resolv.conf changes, start using the first
+ * DNS server of it. This is useful to deal with broken
+ * network managing implementations (like NetworkManager),
+ * that when connecting to a VPN place both the VPN DNS
+ * servers and the local ones in /etc/resolv.conf. Without
+ * resetting the DNS server to use back to the first entry we
+ * will continue to use the local one thus being unable to
+ * resolve VPN domains. */
+ manager_set_dns_server(m, m->dns_servers);
+
+ /* Unconditionally flush the cache when /etc/resolv.conf is
+ * modified, even if the data it contained was completely
+ * identical to the previous version we used. We do this
+ * because altering /etc/resolv.conf is typically done when
+ * the network configuration changes, and that should be
+ * enough to flush the global unicast DNS cache. */
+ if (m->unicast_scope)
+ dns_cache_flush(&m->unicast_scope->cache);
+
+ return 0;
+
+clear:
+ dns_server_unlink_all(m->dns_servers);
+ dns_search_domain_unlink_all(m->search_domains);
+ return r;
+}
+
+static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(s);
+ assert(f);
+ assert(count);
+
+ r = in_addr_to_string(s->family, &s->address, &t);
+ if (r < 0) {
+ log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
+ return;
+ }
+
+ if (*count == MAXNS)
+ fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
+ (*count) ++;
+
+ fprintf(f, "nameserver %s\n", t);
+}
+
+static void write_resolv_conf_search(
+ const char *domain,
+ FILE *f,
+ unsigned *count,
+ unsigned *length) {
+
+ assert(domain);
+ assert(f);
+ assert(length);
+
+ if (*count >= MAXDNSRCH ||
+ *length + strlen(domain) > 256) {
+ if (*count == MAXDNSRCH)
+ fputs(" # Too many search domains configured, remaining ones ignored.", f);
+ if (*length <= 256)
+ fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
+
+ return;
+ }
+
+ (*length) += strlen(domain);
+ (*count) ++;
+
+ fputc(' ', f);
+ fputs(domain, f);
+}
+
+static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
+ Iterator i;
+
+ fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
+ "# Third party programs must not access this file directly, but\n"
+ "# only through the symlink at /etc/resolv.conf. To manage\n"
+ "# resolv.conf(5) in a different way, replace the symlink by a\n"
+ "# static file or a different symlink.\n\n", f);
+
+ if (ordered_set_isempty(dns))
+ fputs("# No DNS servers known.\n", f);
+ else {
+ unsigned count = 0;
+ DnsServer *s;
+
+ ORDERED_SET_FOREACH(s, dns, i)
+ write_resolv_conf_server(s, f, &count);
+ }
+
+ if (!ordered_set_isempty(domains)) {
+ unsigned length = 0, count = 0;
+ char *domain;
+
+ fputs("search", f);
+ ORDERED_SET_FOREACH(domain, domains, i)
+ write_resolv_conf_search(domain, f, &count, &length);
+ fputs("\n", f);
+ }
+
+ return fflush_and_check(f);
+}
+
+int manager_write_resolv_conf(Manager *m) {
+
+ #define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
+
+ _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
+ _cleanup_free_ char *temp_path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ assert(m);
+
+ /* Read the system /etc/resolv.conf first */
+ manager_read_resolv_conf(m);
+
+ /* Add the full list to a set, to filter out duplicates */
+ r = manager_compile_dns_servers(m, &dns);
+ if (r < 0)
+ return r;
+
+ r = manager_compile_search_domains(m, &domains);
+ if (r < 0)
+ return r;
+
+ r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ fchmod(fileno(f), 0644);
+
+ r = write_resolv_conf_contents(f, dns, domains);
+ if (r < 0)
+ goto fail;
+
+ if (rename(temp_path, PRIVATE_RESOLV_CONF) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ (void) unlink(PRIVATE_RESOLV_CONF);
+ (void) unlink(temp_path);
+ return r;
+}
diff --git a/src/resolve/resolved-resolv-conf.h b/src/resolve/resolved-resolv-conf.h
new file mode 100644
index 0000000000..a3355e994b
--- /dev/null
+++ b/src/resolve/resolved-resolv-conf.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "resolved-manager.h"
+
+int manager_read_resolv_conf(Manager *m);
+int manager_write_resolv_conf(Manager *m);
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 7ba0546f4a..be406b71fe 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -26,6 +26,7 @@
#include "mkdir.h"
#include "resolved-conf.h"
#include "resolved-manager.h"
+#include "resolved-resolv-conf.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "user-util.h"
@@ -81,8 +82,10 @@ int main(int argc, char *argv[]) {
}
r = manager_parse_config_file(m);
- if (r < 0)
- log_warning_errno(r, "Failed to parse configuration file: %m");
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse configuration file: %m");
+ goto finish;
+ }
r = manager_start(m);
if (r < 0) {
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
index 3eb19e42b7..39ecf83217 100644
--- a/src/resolve/resolved.conf.in
+++ b/src/resolve/resolved.conf.in
@@ -14,4 +14,5 @@
[Resolve]
#DNS=
#FallbackDNS=@DNS_SERVERS@
+#Domains=
#LLMNR=yes
diff --git a/src/run/run.c b/src/run/run.c
index 38a482bb11..e1accc467b 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -33,6 +33,7 @@
#include "event-util.h"
#include "fd-util.h"
#include "formats-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "ptyfwd.h"
#include "signal-util.h"
@@ -41,7 +42,6 @@
#include "terminal-util.h"
#include "unit-name.h"
#include "user-util.h"
-#include "parse-util.h"
static bool arg_ask_password = true;
static bool arg_scope = false;
@@ -648,6 +648,11 @@ static int transient_timer_set_properties(sd_bus_message *m) {
if (r < 0)
return r;
+ /* Automatically clean up our transient timers */
+ r = sd_bus_message_append(m, "(sv)", "RemainAfterElapse", "b", false);
+ if (r < 0)
+ return r;
+
if (arg_on_active) {
r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active);
if (r < 0)
@@ -687,6 +692,51 @@ static int transient_timer_set_properties(sd_bus_message *m) {
return 0;
}
+static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
+ const char *unique, *id;
+ char *p;
+ int r;
+
+ assert(bus);
+ assert(t >= 0);
+ assert(t < _UNIT_TYPE_MAX);
+
+ r = sd_bus_get_unique_name(bus, &unique);
+ if (r < 0) {
+ sd_id128_t rnd;
+
+ /* We couldn't get the unique name, which is a pretty
+ * common case if we are connected to systemd
+ * directly. In that case, just pick a random uuid as
+ * name */
+
+ r = sd_id128_randomize(&rnd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate random run unit name: %m");
+
+ if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
+ return log_oom();
+
+ return 0;
+ }
+
+ /* We managed to get the unique name, then let's use that to
+ * name our transient units. */
+
+ id = startswith(unique, ":1.");
+ if (!id) {
+ log_error("Unique name %s has unexpected format.", unique);
+ return -EINVAL;
+ }
+
+ p = strjoin("run-u", id, ".", unit_type_to_string(t), NULL);
+ if (!p)
+ return log_oom();
+
+ *ret = p;
+ return 0;
+}
+
static int start_transient_service(
sd_bus *bus,
char **argv) {
@@ -763,8 +813,11 @@ static int start_transient_service(
r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
- return log_oom();
+ } else {
+ r = make_unit_name(bus, UNIT_SERVICE, &service);
+ if (r < 0)
+ return r;
+ }
r = sd_bus_message_new_method_call(
bus,
@@ -882,8 +935,11 @@ static int start_transient_scope(
r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope);
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
- } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
- return log_oom();
+ } else {
+ r = make_unit_name(bus, UNIT_SCOPE, &scope);
+ if (r < 0)
+ return r;
+ }
r = sd_bus_message_new_method_call(
bus,
@@ -1052,9 +1108,15 @@ static int start_transient_timer(
break;
}
- } else if ((asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) ||
- (asprintf(&timer, "run-"PID_FMT".timer", getpid()) < 0))
- return log_oom();
+ } else {
+ r = make_unit_name(bus, UNIT_SERVICE, &service);
+ if (r < 0)
+ return r;
+
+ r = unit_name_change_suffix(service, ".timer", &timer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to change unit suffix: %m");
+ }
r = sd_bus_message_new_method_call(
bus,
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c
index 79f5a60579..35f2e1b67d 100644
--- a/src/shared/acl-util.c
+++ b/src/shared/acl-util.c
@@ -22,8 +22,8 @@
#include <errno.h>
#include <stdbool.h>
-#include "alloc-util.h"
#include "acl-util.h"
+#include "alloc-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h
index cf612e8722..256a6a5900 100644
--- a/src/shared/acl-util.h
+++ b/src/shared/acl-util.h
@@ -23,9 +23,9 @@
#ifdef HAVE_ACL
+#include <acl/libacl.h>
#include <stdbool.h>
#include <sys/acl.h>
-#include <acl/libacl.h>
#include "macro.h"
diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c
index 8e36067f74..30e03c0652 100644
--- a/src/shared/acpi-fpdt.c
+++ b/src/shared/acpi-fpdt.c
@@ -25,8 +25,8 @@
#include <string.h>
#include <unistd.h>
-#include "alloc-util.h"
#include "acpi-fpdt.h"
+#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "time-util.h"
diff --git a/src/shared/architecture.c b/src/shared/architecture.c
index e2efa4272b..73937bd5a7 100644
--- a/src/shared/architecture.c
+++ b/src/shared/architecture.c
@@ -21,9 +21,9 @@
#include <sys/utsname.h>
+#include "architecture.h"
#include "string-table.h"
#include "string-util.h"
-#include "architecture.h"
int uname_architecture(void) {
diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c
index ecbe1aaa0f..879aca9374 100644
--- a/src/shared/boot-timestamps.c
+++ b/src/shared/boot-timestamps.c
@@ -20,8 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "boot-timestamps.h"
#include "acpi-fpdt.h"
+#include "boot-timestamps.h"
#include "efivars.h"
int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 73ceeba18f..8775808da4 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1428,16 +1428,36 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
return 0;
+
} else if (streq(field, "EnvironmentFile")) {
+
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles");
if (r < 0)
- return r;
+ return bus_log_create_error(r);
r = sd_bus_message_append(m, "v", "a(sb)", 1,
eq[0] == '-' ? eq + 1 : eq,
eq[0] == '-');
if (r < 0)
- return r;
+ return bus_log_create_error(r);
+
+ return 0;
+
+ } else if (streq(field, "RandomizedDelaySec")) {
+ usec_t t;
+
+ r = parse_sec(eq, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "v", "t", t);
+ if (r < 0)
+ return bus_log_create_error(r);
+
return 0;
}
@@ -1450,13 +1470,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
- "SyslogLevelPrefix", "Delegate")) {
+ "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
r = parse_boolean(eq);
- if (r < 0) {
- log_error("Failed to parse boolean assignment %s.", assignment);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
r = sd_bus_message_append(m, "v", "b", r);
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index aa832454b5..5842bdd15e 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <sys/types.h>
+
#include "logs-show.h"
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index 835fe52423..71cc613704 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -29,13 +29,13 @@
#include <sys/stat.h>
#include "clean-ipc.h"
+#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-#include "dirent-util.h"
static int clean_sysvipc_shm(uid_t delete_uid) {
_cleanup_fclose_ FILE *f = NULL;
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index fb0234baae..2872b22d9d 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdbool.h>
+#include <stdio.h>
#include "macro.h"
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 7af15e0098..4cf6355b71 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -29,6 +29,8 @@
#include "hexdecoct.h"
#include "parse-util.h"
#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
int dns_label_unescape(const char **name, char *dest, size_t sz) {
const char *n;
@@ -180,30 +182,31 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
return r;
}
-int dns_label_escape(const char *p, size_t l, char **ret) {
- _cleanup_free_ char *s = NULL;
+int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
char *q;
- int r;
-
- assert(p);
- assert(ret);
if (l > DNS_LABEL_MAX)
return -EINVAL;
+ if (sz < 1)
+ return -ENOSPC;
- s = malloc(l * 4 + 1);
- if (!s)
- return -ENOMEM;
+ assert(p);
+ assert(dest);
- q = s;
+ q = dest;
while (l > 0) {
if (*p == '.' || *p == '\\') {
+ if (sz < 3)
+ return -ENOSPC;
+
/* Dot or backslash */
*(q++) = '\\';
*(q++) = *p;
+ sz -= 2;
+
} else if (*p == '_' ||
*p == '-' ||
(*p >= '0' && *p <= '9') ||
@@ -211,15 +214,27 @@ int dns_label_escape(const char *p, size_t l, char **ret) {
(*p >= 'A' && *p <= 'Z')) {
/* Proper character */
+
+ if (sz < 2)
+ return -ENOSPC;
+
*(q++) = *p;
+ sz -= 1;
+
} else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
/* Everything else */
+
+ if (sz < 5)
+ return -ENOSPC;
+
*(q++) = '\\';
*(q++) = '0' + (char) ((uint8_t) *p / 100);
*(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
*(q++) = '0' + (char) ((uint8_t) *p % 10);
+ sz -= 4;
+
} else
return -EINVAL;
@@ -228,8 +243,28 @@ int dns_label_escape(const char *p, size_t l, char **ret) {
}
*q = 0;
+ return (int) (q - dest);
+}
+
+int dns_label_escape_new(const char *p, size_t l, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ if (l > DNS_LABEL_MAX)
+ return -EINVAL;
+
+ s = new(char, DNS_LABEL_ESCAPED_MAX);
+ if (!s)
+ return -ENOMEM;
+
+ r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ return r;
+
*ret = s;
- r = q - s;
s = NULL;
return r;
@@ -349,28 +384,32 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
if (k > 0)
r = k;
- r = dns_label_escape(label, r, &t);
- if (r < 0)
- return r;
-
if (_ret) {
- if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
+ r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ return r;
+
if (!first)
- ret[n++] = '.';
- else
- first = false;
+ ret[n] = '.';
+ } else {
+ char escaped[DNS_LABEL_ESCAPED_MAX];
- memcpy(ret + n, t, r);
+ r = dns_label_escape(label, r, escaped, sizeof(escaped));
+ if (r < 0)
+ return r;
}
+ if (!first)
+ n++;
+ else
+ first = false;
+
n += r;
}
- if (n > DNS_NAME_MAX)
- return -EINVAL;
-
if (_ret) {
if (!GREEDY_REALLOC(ret, allocated, n + 1))
return -ENOMEM;
@@ -546,6 +585,73 @@ int dns_name_endswith(const char *name, const char *suffix) {
}
}
+int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
+ const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
+ int r, q, k, w;
+
+ assert(name);
+ assert(old_suffix);
+ assert(new_suffix);
+ assert(ret);
+
+ n = name;
+ s = old_suffix;
+
+ for (;;) {
+ char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1];
+
+ if (!saved_before)
+ saved_before = n;
+
+ r = dns_label_unescape(&n, ln, sizeof(ln));
+ if (r < 0)
+ return r;
+ k = dns_label_undo_idna(ln, r, ln, sizeof(ln));
+ if (k < 0)
+ return k;
+ if (k > 0)
+ r = k;
+
+ if (!saved_after)
+ saved_after = n;
+
+ q = dns_label_unescape(&s, ls, sizeof(ls));
+ if (q < 0)
+ return q;
+ w = dns_label_undo_idna(ls, q, ls, sizeof(ls));
+ if (w < 0)
+ return w;
+ if (w > 0)
+ q = w;
+
+ if (r == 0 && q == 0)
+ break;
+ if (r == 0 && saved_after == n) {
+ *ret = NULL; /* doesn't match */
+ return 0;
+ }
+
+ ln[r] = ls[q] = 0;
+
+ if (r != q || strcasecmp(ln, ls)) {
+
+ /* Not the same, let's jump back, and try with the next label again */
+ s = old_suffix;
+ n = saved_after;
+ saved_after = saved_before = NULL;
+ }
+ }
+
+ /* Found it! Now generate the new name */
+ prefix = strndupa(name, saved_before - name);
+
+ r = dns_name_concat(prefix, new_suffix, ret);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
int dns_name_between(const char *a, const char *b, const char *c) {
int n;
@@ -684,34 +790,283 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
return 0;
}
-int dns_name_root(const char *name) {
- char label[DNS_LABEL_MAX+1];
- int r;
+bool dns_name_is_root(const char *name) {
assert(name);
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
+ /* There are exactly two ways to encode the root domain name:
+ * as empty string, or with a single dot. */
- return r == 0 && *name == 0;
+ return STR_IN_SET(name, "", ".");
}
-int dns_name_single_label(const char *name) {
+bool dns_name_is_single_label(const char *name) {
char label[DNS_LABEL_MAX+1];
int r;
assert(name);
r = dns_label_unescape(&name, label, sizeof(label));
+ if (r <= 0)
+ return false;
+
+ return dns_name_is_root(name);
+}
+
+/* Encode a domain name according to RFC 1035 Section 3.1 */
+int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) {
+ uint8_t *label_length;
+ uint8_t *out;
+ int r;
+
+ assert_return(buffer, -EINVAL);
+ assert_return(domain, -EINVAL);
+ assert_return(domain[0], -EINVAL);
+
+ out = buffer;
+
+ do {
+ /* reserve a byte for label length */
+ if (len == 0)
+ return -ENOBUFS;
+ len--;
+ label_length = out;
+ out++;
+
+ /* convert and copy a single label */
+ r = dns_label_unescape(&domain, (char *) out, len);
+ if (r < 0)
+ return r;
+
+ /* fill label length, move forward */
+ *label_length = r;
+ out += r;
+ len -= r;
+ } while (r != 0);
+
+ return out - buffer;
+}
+
+static bool srv_type_label_is_valid(const char *label, size_t n) {
+ size_t k;
+
+ assert(label);
+
+ if (n < 2) /* Label needs to be at least 2 chars long */
+ return false;
+
+ if (label[0] != '_') /* First label char needs to be underscore */
+ return false;
+
+ /* Second char must be a letter */
+ if (!(label[1] >= 'A' && label[1] <= 'Z') &&
+ !(label[1] >= 'a' && label[1] <= 'z'))
+ return false;
+
+ /* Third and further chars must be alphanumeric or a hyphen */
+ for (k = 2; k < n; k++) {
+ if (!(label[k] >= 'A' && label[k] <= 'Z') &&
+ !(label[k] >= 'a' && label[k] <= 'z') &&
+ !(label[k] >= '0' && label[k] <= '9') &&
+ label[k] != '-')
+ return false;
+ }
+
+ return true;
+}
+
+bool dns_srv_type_is_valid(const char *name) {
+ unsigned c = 0;
+ int r;
+
+ if (!name)
+ return false;
+
+ for (;;) {
+ char label[DNS_LABEL_MAX];
+
+ /* This more or less implements RFC 6335, Section 5.1 */
+
+ r = dns_label_unescape(&name, label, sizeof(label));
+ if (r < 0)
+ return false;
+ if (r == 0)
+ break;
+
+ if (c >= 2)
+ return false;
+
+ if (!srv_type_label_is_valid(label, r))
+ return false;
+
+ c++;
+ }
+
+ return c == 2; /* exactly two labels */
+}
+
+bool dns_service_name_is_valid(const char *name) {
+ size_t l;
+
+ /* This more or less implements RFC 6763, Section 4.1.1 */
+
+ if (!name)
+ return false;
+
+ if (!utf8_is_valid(name))
+ return false;
+
+ if (string_has_cc(name, NULL))
+ return false;
+
+ l = strlen(name);
+ if (l <= 0)
+ return false;
+ if (l > 63)
+ return false;
+
+ return true;
+}
+
+int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
+ char escaped[DNS_LABEL_ESCAPED_MAX];
+ _cleanup_free_ char *n = NULL;
+ int r;
+
+ assert(type);
+ assert(domain);
+ assert(ret);
+
+ if (!dns_srv_type_is_valid(type))
+ return -EINVAL;
+
+ if (!name)
+ return dns_name_concat(type, domain, ret);
+
+ if (!dns_service_name_is_valid(name))
+ return -EINVAL;
+
+ r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
if (r < 0)
return r;
- if (r == 0)
- return 0;
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_name_concat(type, domain, &n);
if (r < 0)
return r;
- return r == 0 && *name == 0;
+ return dns_name_concat(escaped, n, ret);
+}
+
+static bool dns_service_name_label_is_valid(const char *label, size_t n) {
+ char *s;
+
+ assert(label);
+
+ if (memchr(label, 0, n))
+ return false;
+
+ s = strndupa(label, n);
+ return dns_service_name_is_valid(s);
+}
+
+int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
+ _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
+ const char *p = joined, *q = NULL, *d = NULL;
+ char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
+ int an, bn, cn, r;
+ unsigned x = 0;
+
+ assert(joined);
+
+ /* Get first label from the full name */
+ an = dns_label_unescape(&p, a, sizeof(a));
+ if (an < 0)
+ return an;
+
+ if (an > 0) {
+ x++;
+
+ /* If there was a first label, try to get the second one */
+ bn = dns_label_unescape(&p, b, sizeof(b));
+ if (bn < 0)
+ return bn;
+
+ if (bn > 0) {
+ x++;
+
+ /* If there was a second label, try to get the third one */
+ q = p;
+ cn = dns_label_unescape(&p, c, sizeof(c));
+ if (cn < 0)
+ return cn;
+
+ if (cn > 0)
+ x++;
+ } else
+ cn = 0;
+ } else
+ an = 0;
+
+ if (x >= 2 && srv_type_label_is_valid(b, bn)) {
+
+ if (x >= 3 && srv_type_label_is_valid(c, cn)) {
+
+ if (dns_service_name_label_is_valid(a, an)) {
+
+ /* OK, got <name> . <type> . <type2> . <domain> */
+
+ name = strndup(a, an);
+ if (!name)
+ return -ENOMEM;
+
+ type = new(char, bn+1+cn+1);
+ if (!type)
+ return -ENOMEM;
+ strcpy(stpcpy(stpcpy(type, b), "."), c);
+
+ d = p;
+ goto finish;
+ }
+
+ } else if (srv_type_label_is_valid(a, an)) {
+
+ /* OK, got <type> . <type2> . <domain> */
+
+ name = NULL;
+
+ type = new(char, an+1+bn+1);
+ if (!type)
+ return -ENOMEM;
+ strcpy(stpcpy(stpcpy(type, a), "."), b);
+
+ d = q;
+ goto finish;
+ }
+ }
+
+ name = NULL;
+ type = NULL;
+ d = joined;
+
+finish:
+ r = dns_name_normalize(d, &domain);
+ if (r < 0)
+ return r;
+
+ if (_domain) {
+ *_domain = domain;
+ domain = NULL;
+ }
+
+ if (_type) {
+ *_type = type;
+ type = NULL;
+ }
+
+ if (_name) {
+ *_name = name;
+ name = NULL;
+ }
+
+ return 0;
}
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 1f0d242c18..99c72574db 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -26,11 +26,12 @@
#include "in-addr-util.h"
#define DNS_LABEL_MAX 63
-#define DNS_NAME_MAX 255
+#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1)
int dns_label_unescape(const char **name, char *dest, size_t sz);
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
-int dns_label_escape(const char *p, size_t l, char **ret);
+int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
+int dns_label_escape_new(const char *p, size_t l, char **ret);
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
@@ -62,8 +63,18 @@ int dns_name_between(const char *a, const char *b, const char *c);
int dns_name_equal(const char *x, const char *y);
int dns_name_endswith(const char *name, const char *suffix);
+int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret);
+
int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
int dns_name_address(const char *p, int *family, union in_addr_union *a);
-int dns_name_root(const char *name);
-int dns_name_single_label(const char *name);
+bool dns_name_is_root(const char *name);
+bool dns_name_is_single_label(const char *name);
+
+int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len);
+
+bool dns_srv_type_is_valid(const char *name);
+bool dns_service_name_is_valid(const char *name);
+
+int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
+int dns_service_split(const char *joined, char **name, char **type, char **domain);
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index 86bb0b57c3..89deeb9b55 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <string.h>
#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "dirent-util.h"
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index e953a12737..5cb4c3af4e 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include "sd-id128.h"
+
#include "time-util.h"
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index e178287872..5acfb0191b 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <arpa/inet.h>
#include <net/if.h>
+#include <sys/types.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
diff --git a/src/shared/install.c b/src/shared/install.c
index 9b6464ba9d..17e03e59cd 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -942,7 +942,7 @@ static int unit_file_load(
if (fstat(fd, &st) < 0)
return -errno;
if (null_or_empty(&st)) {
- info->type = UNIT_FILE_MASKED;
+ info->type = UNIT_FILE_TYPE_MASKED;
return 0;
}
if (S_ISDIR(st.st_mode))
diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h
index 569e1faa55..98927bbc59 100644
--- a/src/shared/logs-show.h
+++ b/src/shared/logs-show.h
@@ -26,8 +26,8 @@
#include "sd-journal.h"
-#include "util.h"
#include "output-mode.h"
+#include "util.h"
int output_journal(
FILE *f,
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index f041600fbf..038db7453c 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "time-util.h"
-#include "lockfile-util.h"
#include "hashmap.h"
+#include "lockfile-util.h"
+#include "time-util.h"
typedef enum ImageType {
IMAGE_DIRECTORY,
diff --git a/src/shared/nss-util.h b/src/shared/nss-util.h
index 3657aa5d9c..a7b51a91da 100644
--- a/src/shared/nss-util.h
+++ b/src/shared/nss-util.h
@@ -21,11 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <nss.h>
+#include <grp.h>
#include <netdb.h>
-#include <resolv.h>
+#include <nss.h>
#include <pwd.h>
-#include <grp.h>
+#include <resolv.h>
#define NSS_GETHOSTBYNAME_PROTOTYPES(module) \
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index d71f379e76..4a82bd18cd 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -19,18 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include "alloc-util.h"
-#include "util.h"
-#include "strv.h"
-#include "path-util.h"
#include "install.h"
-#include "string-util.h"
#include "path-lookup.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
int user_config_home(char **config_home) {
const char *e;
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 63e81f4894..2666b8f7e2 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <limits.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
-#include <limits.h>
#include <termios.h>
#include "alloc-util.h"
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index c518cf83ec..09baf51661 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -21,9 +21,9 @@
#include <seccomp.h>
+#include "seccomp-util.h"
#include "string-util.h"
#include "util.h"
-#include "seccomp-util.h"
const char* seccomp_arch_to_string(uint32_t c) {
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index 29db855c67..3fcea61873 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -25,8 +25,8 @@
#include "log.h"
#include "process-util.h"
-#include "util.h"
#include "spawn-ask-password-agent.h"
+#include "util.h"
static pid_t agent_pid = 0;
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index ec6e5a8312..8ea6cb830b 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -19,11 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
#include <errno.h>
#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "fd-util.h"
#include "io-util.h"
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
index 21cb82ea1c..70caa542e7 100644
--- a/src/shared/sysctl-util.c
+++ b/src/shared/sysctl-util.c
@@ -30,8 +30,8 @@
#include "fileio.h"
#include "log.h"
#include "string-util.h"
-#include "util.h"
#include "sysctl-util.h"
+#include "util.h"
char *sysctl_normalize(char *s) {
char *n;
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
index d58f9873d5..7131e94cdb 100644
--- a/src/shared/watchdog.c
+++ b/src/shared/watchdog.c
@@ -19,15 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/watchdog.h>
-#include "watchdog.h"
-#include "log.h"
#include "fd-util.h"
+#include "log.h"
+#include "watchdog.h"
static int watchdog_fd = -1;
static usec_t watchdog_timeout = USEC_INFINITY;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 51b82d57db..f478d809c2 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3360,6 +3360,7 @@ typedef struct UnitStatusInfo {
usec_t inactive_enter_timestamp;
bool need_daemon_reload;
+ bool transient;
/* Service */
pid_t main_pid;
@@ -3459,7 +3460,7 @@ static void print_status_info(
path = i->source_path ? i->source_path : i->fragment_path;
- if (i->load_error)
+ if (i->load_error != 0)
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) && !isempty(i->unit_file_preset))
@@ -3475,6 +3476,9 @@ static void print_status_info(
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;
@@ -3839,6 +3843,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->condition_result = b;
else if (streq(name, "AssertResult"))
i->assert_result = b;
+ else if (streq(name, "Transient"))
+ i->transient = b;
break;
}
@@ -4646,8 +4652,7 @@ static int show(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- if (show_properties)
- pager_open_if_enabled();
+ pager_open_if_enabled();
if (show_status)
/* Increase max number of open files to 16K if we can, we
@@ -6545,8 +6550,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return version();
case 't': {
- if (isempty(optarg))
- return log_error_errno(r, "--type requires arguments.");
+ if (isempty(optarg)) {
+ log_error("--type requires arguments.");
+ return -EINVAL;
+ }
p = optarg;
for(;;) {
@@ -6778,8 +6785,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_STATE: {
- if (isempty(optarg))
- return log_error_errno(r, "--signal requires arguments.");
+ if (isempty(optarg)) {
+ log_error("--signal requires arguments.");
+ return -EINVAL;
+ }
p = optarg;
for(;;) {
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 43cf247cdf..d8adf59aca 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -27,8 +27,9 @@
#include <sys/types.h>
#include <sys/uio.h>
-#include "sd-id128.h"
#include "sd-event.h"
+#include "sd-id128.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index 214e77cab1..c26cd1be3a 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -22,8 +22,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
#include "_sd-common.h"
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index fc11725821..edf80563ac 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -23,8 +23,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
#include "_sd-common.h"
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index c0146158f3..fc1d70e738 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -27,8 +27,8 @@
#include <netinet/in.h>
#include <sys/types.h>
-#include "sd-event.h"
#include "sd-dhcp-lease.h"
+#include "sd-event.h"
#include "_sd-common.h"
diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h
index 55bceb1ea5..56b63c38da 100644
--- a/src/systemd/sd-dhcp-server.h
+++ b/src/systemd/sd-dhcp-server.h
@@ -27,6 +27,7 @@
#include <netinet/in.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 9f0e92806e..29e95e2492 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -26,8 +26,8 @@
#include <net/ethernet.h>
#include <sys/types.h>
-#include "sd-event.h"
#include "sd-dhcp6-lease.h"
+#include "sd-event.h"
#include "_sd-common.h"
@@ -49,6 +49,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
sd_dhcp6_client_cb_t cb, void *userdata);
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
+int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type);
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 565de5495a..fb97f7f28d 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -22,11 +22,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/signalfd.h>
-#include <sys/epoll.h>
#include <inttypes.h>
#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+#include <sys/types.h>
#include "_sd-common.h"
@@ -56,7 +56,8 @@ enum {
SD_EVENT_PENDING,
SD_EVENT_RUNNING,
SD_EVENT_EXITING,
- SD_EVENT_FINISHED
+ SD_EVENT_FINISHED,
+ SD_EVENT_PREPARING,
};
enum {
@@ -87,9 +88,9 @@ int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callb
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_prepare(sd_event *e);
-int sd_event_wait(sd_event *e, uint64_t timeout);
+int sd_event_wait(sd_event *e, uint64_t usec);
int sd_event_dispatch(sd_event *e);
-int sd_event_run(sd_event *e, uint64_t timeout);
+int sd_event_run(sd_event *e, uint64_t usec);
int sd_event_loop(sd_event *e);
int sd_event_exit(sd_event *e, int code);
diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h
index 6337d61452..c1e79640eb 100644
--- a/src/systemd/sd-ipv4acd.h
+++ b/src/systemd/sd-ipv4acd.h
@@ -23,10 +23,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/in.h>
#include <net/ethernet.h>
+#include <netinet/in.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index 2949f1dfb2..1d25f02bd0 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -22,10 +22,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/in.h>
#include <net/ethernet.h>
+#include <netinet/in.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h
index 00237a2158..facb6d8a95 100644
--- a/src/systemd/sd-journal.h
+++ b/src/systemd/sd-journal.h
@@ -23,12 +23,13 @@
***/
#include <inttypes.h>
-#include <sys/types.h>
#include <stdarg.h>
+#include <sys/types.h>
#include <sys/uio.h>
#include <syslog.h>
#include "sd-id128.h"
+
#include "_sd-common.h"
/* Journal APIs. See sd-journal(3) for more information. */
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index 31651ce132..16d297a52d 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -23,10 +23,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/ethernet.h>
#include <inttypes.h>
+#include <net/ethernet.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 59c6eedcda..2ad6bcb357 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -22,8 +22,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
#include "_sd-common.h"
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index 8aedaec6d1..072832a916 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -23,6 +23,7 @@
***/
#include "sd-id128.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
index 80e24325f7..71e65d4425 100644
--- a/src/systemd/sd-ndisc.h
+++ b/src/systemd/sd-ndisc.h
@@ -26,6 +26,7 @@
#include <net/ethernet.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index 2960deda0a..dd5cc04ca6 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -23,12 +23,13 @@
***/
#include <inttypes.h>
-#include <netinet/in.h>
#include <netinet/ether.h>
+#include <netinet/in.h>
#include <linux/rtnetlink.h>
#include <linux/neighbour.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 4179015fbf..076f45745d 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -23,8 +23,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <inttypes.h>
+#include <sys/types.h>
#include "_sd-common.h"
diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h
index 82c4b39efe..bfe32102f8 100644
--- a/src/systemd/sd-resolve.h
+++ b/src/systemd/sd-resolve.h
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include "sd-event.h"
+
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c
index a5b66a7d2f..35479d67c1 100644
--- a/src/test/test-architecture.c
+++ b/src/test/test-architecture.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "virt.h"
#include "architecture.h"
-#include "util.h"
#include "log.h"
+#include "util.h"
+#include "virt.h"
int main(int argc, char *argv[]) {
int a, v;
diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c
index 06d93af533..fab33d20c7 100644
--- a/src/test/test-boot-timestamps.c
+++ b/src/test/test-boot-timestamps.c
@@ -20,11 +20,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "log.h"
+#include "acpi-fpdt.h"
#include "boot-timestamps.h"
#include "efivars.h"
-#include "acpi-fpdt.h"
+#include "log.h"
+#include "util.h"
static int test_acpi_fpdt(void) {
usec_t loader_start;
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 70819b0371..9cef7154c6 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -75,7 +75,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_
u = after;
r = calendar_spec_next_usec(c, after, &u);
- printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
+ printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof(buf), u));
if (expect != (usec_t)-1)
assert_se(r >= 0 && u == expect);
else
@@ -123,6 +123,9 @@ int main(int argc, char* argv[]) {
test_one("annually", "*-01-01 00:00:00");
test_one("*:2/3", "*-*-* *:02/3:00");
test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+ test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
+ test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
+ test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
@@ -131,11 +134,19 @@ int main(int argc, char* argv[]) {
test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00.420000001 UTC", "EET", 12345, 1459048620420000);
+ test_next("2016-03-27 03:17:00.4200005 UTC", "EET", 12345, 1459048620420001);
+ test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000);
+ test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000);
+ test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000);
assert_se(calendar_spec_from_string("test", &c) < 0);
assert_se(calendar_spec_from_string("", &c) < 0);
assert_se(calendar_spec_from_string("7", &c) < 0);
assert_se(calendar_spec_from_string("121212:1:2", &c) < 0);
+ assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0);
+ assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0);
+ assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0);
return 0;
}
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index de6c421b82..2746013522 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -21,10 +21,10 @@
#include <stdio.h>
-#include "manager.h"
-#include "unit.h"
#include "macro.h"
+#include "manager.h"
#include "test-helper.h"
+#include "unit.h"
static int test_cgroup_mask(void) {
Manager *m = NULL;
@@ -40,6 +40,16 @@ static int test_cgroup_mask(void) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
}
+
+ /* Turn off all kinds of default accouning, so that we can
+ * verify the masks resulting of our configuration and nothing
+ * else. */
+ m->default_cpu_accounting =
+ m->default_memory_accounting =
+ m->default_blockio_accounting =
+ m->default_tasks_accounting = false;
+ m->default_tasks_max = (uint64_t) -1;
+
assert_se(r >= 0);
assert_se(manager_startup(m, serial, fdset) >= 0);
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index d5778748a0..f010e4e19a 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -52,6 +52,36 @@ static void test_dns_label_unescape(void) {
test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
}
+static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
+ uint8_t buffer[buffer_sz];
+ int r;
+
+ r = dns_name_to_wire_format(what, buffer, buffer_sz);
+ assert_se(r == ret);
+
+ if (r < 0)
+ return;
+
+ assert_se(!memcmp(buffer, expect, r));
+}
+
+static void test_dns_name_to_wire_format(void) {
+ const char out1[] = { 3, 'f', 'o', 'o', 0 };
+ const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 };
+ const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 };
+
+ test_dns_name_to_wire_format_one("", NULL, 0, -EINVAL);
+
+ test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1));
+ test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) + 1, sizeof(out1));
+ test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) - 1, -ENOBUFS);
+
+ test_dns_name_to_wire_format_one("hallo.foo.bar", out2, sizeof(out2), sizeof(out2));
+ test_dns_name_to_wire_format_one("hallo.foo..bar", NULL, 32, -EINVAL);
+
+ test_dns_name_to_wire_format_one("\\032foo.bar", out3, sizeof(out3), sizeof(out3));
+}
+
static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) {
char buffer[buffer_sz];
const char *label;
@@ -96,7 +126,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
_cleanup_free_ char *t = NULL;
int r;
- r = dns_label_escape(what, l, &t);
+ r = dns_label_escape_new(what, l, &t);
assert_se(r == ret);
if (r < 0)
@@ -216,21 +246,21 @@ static void test_dns_name_endswith(void) {
test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL);
}
-static void test_dns_name_root(void) {
- assert_se(dns_name_root("") == true);
- assert_se(dns_name_root(".") == true);
- assert_se(dns_name_root("xxx") == false);
- assert_se(dns_name_root("xxx.") == false);
- assert_se(dns_name_root("..") == -EINVAL);
+static void test_dns_name_is_root(void) {
+ assert_se(dns_name_is_root(""));
+ assert_se(dns_name_is_root("."));
+ assert_se(!dns_name_is_root("xxx"));
+ assert_se(!dns_name_is_root("xxx."));
+ assert_se(!dns_name_is_root(".."));
}
-static void test_dns_name_single_label(void) {
- assert_se(dns_name_single_label("") == false);
- assert_se(dns_name_single_label(".") == false);
- assert_se(dns_name_single_label("..") == -EINVAL);
- assert_se(dns_name_single_label("x") == true);
- assert_se(dns_name_single_label("x.") == true);
- assert_se(dns_name_single_label("xx.yy") == false);
+static void test_dns_name_is_single_label(void) {
+ assert_se(!dns_name_is_single_label(""));
+ assert_se(!dns_name_is_single_label("."));
+ assert_se(!dns_name_is_single_label(".."));
+ assert_se(dns_name_is_single_label("x"));
+ assert_se(dns_name_is_single_label("x."));
+ assert_se(!dns_name_is_single_label("xx.yy"));
}
static void test_dns_name_reverse_one(const char *address, const char *name) {
@@ -286,6 +316,117 @@ static void test_dns_name_is_valid(void) {
test_dns_name_is_valid_one("\n", 0);
}
+static void test_dns_service_name_is_valid(void) {
+ assert_se(dns_service_name_is_valid("Lennart's Compüter"));
+ assert_se(dns_service_name_is_valid("piff.paff"));
+
+ assert_se(!dns_service_name_is_valid(NULL));
+ assert_se(!dns_service_name_is_valid(""));
+ assert_se(!dns_service_name_is_valid("foo\nbar"));
+ assert_se(!dns_service_name_is_valid("foo\201bar"));
+ assert_se(!dns_service_name_is_valid("this is an overly long string that is certainly longer than 63 characters"));
+}
+
+static void test_dns_srv_type_is_valid(void) {
+
+ assert_se(dns_srv_type_is_valid("_http._tcp"));
+ assert_se(dns_srv_type_is_valid("_foo-bar._tcp"));
+ assert_se(dns_srv_type_is_valid("_w._udp"));
+ assert_se(dns_srv_type_is_valid("_a800._tcp"));
+ assert_se(dns_srv_type_is_valid("_a-800._tcp"));
+
+ assert_se(!dns_srv_type_is_valid(NULL));
+ assert_se(!dns_srv_type_is_valid(""));
+ assert_se(!dns_srv_type_is_valid("x"));
+ assert_se(!dns_srv_type_is_valid("_foo"));
+ assert_se(!dns_srv_type_is_valid("_tcp"));
+ assert_se(!dns_srv_type_is_valid("_"));
+ assert_se(!dns_srv_type_is_valid("_foo."));
+ assert_se(!dns_srv_type_is_valid("_föo._tcp"));
+ assert_se(!dns_srv_type_is_valid("_f\no._tcp"));
+ assert_se(!dns_srv_type_is_valid("_800._tcp"));
+ assert_se(!dns_srv_type_is_valid("_-800._tcp"));
+ assert_se(!dns_srv_type_is_valid("_-foo._tcp"));
+ assert_se(!dns_srv_type_is_valid("_piep._foo._udp"));
+}
+
+static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) {
+ _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
+
+ assert_se(dns_service_join(a, b, c, &t) == r);
+ assert_se(streq_ptr(t, d));
+
+ if (r < 0)
+ return;
+
+ assert_se(dns_service_split(t, &x, &y, &z) >= 0);
+ assert_se(streq_ptr(a, x));
+ assert_se(streq_ptr(b, y));
+ assert_se(streq_ptr(c, z));
+}
+
+static void test_dns_service_join(void) {
+ test_dns_service_join_one("", "", "", -EINVAL, NULL);
+ test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL);
+ test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL);
+ test_dns_service_join_one("foo", "", "foo", -EINVAL, NULL);
+ test_dns_service_join_one("foo", "foo", "foo", -EINVAL, NULL);
+
+ test_dns_service_join_one("foo", "_http._tcp", "", 0, "foo._http._tcp");
+ test_dns_service_join_one(NULL, "_http._tcp", "", 0, "_http._tcp");
+ test_dns_service_join_one("foo", "_http._tcp", "foo", 0, "foo._http._tcp.foo");
+ test_dns_service_join_one(NULL, "_http._tcp", "foo", 0, "_http._tcp.foo");
+ test_dns_service_join_one("Lennart's PC", "_pc._tcp", "foo.bar.com", 0, "Lennart\\039s\\032PC._pc._tcp.foo.bar.com");
+ test_dns_service_join_one(NULL, "_pc._tcp", "foo.bar.com", 0, "_pc._tcp.foo.bar.com");
+}
+
+static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) {
+ _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
+
+ assert_se(dns_service_split(joined, &x, &y, &z) == r);
+ assert_se(streq_ptr(x, a));
+ assert_se(streq_ptr(y, b));
+ assert_se(streq_ptr(z, c));
+
+ if (r < 0)
+ return;
+
+ if (y) {
+ assert_se(dns_service_join(x, y, z, &t) == 0);
+ assert_se(streq_ptr(joined, t));
+ } else
+ assert_se(!x && streq_ptr(z, joined));
+}
+
+static void test_dns_service_split(void) {
+ test_dns_service_split_one("", NULL, NULL, "", 0);
+ test_dns_service_split_one("foo", NULL, NULL, "foo", 0);
+ test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0);
+ test_dns_service_split_one("_foo.bar", NULL, NULL, "_foo.bar", 0);
+ test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", "", 0);
+ test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", "", 0);
+ test_dns_service_split_one("Wuff\\032Wuff._foo._bar.waldo.com", "Wuff Wuff", "_foo._bar", "waldo.com", 0);
+}
+
+static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r);
+ assert_se(streq_ptr(s, result));
+}
+
+static void test_dns_name_change_suffix(void) {
+ test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo");
+ test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff");
+ test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff");
+ test_dns_name_change_suffix_one("foo.bar.waldi.quux", "waldi.quux", "piff.paff", 1, "foo.bar.piff.paff");
+ test_dns_name_change_suffix_one("foo.bar.waldi.quux", "quux", "piff.paff", 1, "foo.bar.waldi.piff.paff");
+ test_dns_name_change_suffix_one("foo.bar.waldi.quux", "", "piff.paff", 1, "foo.bar.waldi.quux.piff.paff");
+ test_dns_name_change_suffix_one("", "", "piff.paff", 1, "piff.paff");
+ test_dns_name_change_suffix_one("", "", "", 1, "");
+ test_dns_name_change_suffix_one("a", "b", "c", 0, NULL);
+}
+
int main(int argc, char *argv[]) {
test_dns_label_unescape();
@@ -295,11 +436,17 @@ int main(int argc, char *argv[]) {
test_dns_name_equal();
test_dns_name_endswith();
test_dns_name_between();
- test_dns_name_root();
- test_dns_name_single_label();
+ test_dns_name_is_root();
+ test_dns_name_is_single_label();
test_dns_name_reverse();
test_dns_name_concat();
test_dns_name_is_valid();
+ test_dns_name_to_wire_format();
+ test_dns_service_name_is_valid();
+ test_dns_srv_type_is_valid();
+ test_dns_service_join();
+ test_dns_service_split();
+ test_dns_name_change_suffix();
return 0;
}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index 954ed0d9e0..4f14c58788 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -19,12 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
#include <string.h>
-#include "manager.h"
#include "bus-util.h"
+#include "manager.h"
int main(int argc, char *argv[]) {
_cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index bde3c7c3cf..871c71e171 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <fcntl.h>
+#include <stdio.h>
#include <unistd.h>
#include "alloc-util.h"
diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c
index d636e427c4..ff66bde094 100644
--- a/src/test/test-firewall-util.c
+++ b/src/test/test-firewall-util.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
#include "firewall-util.h"
+#include "log.h"
#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))}
diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c
index d0e65001f5..83cea360e6 100644
--- a/src/test/test-hashmap.c
+++ b/src/test/test-hashmap.c
@@ -17,8 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "hashmap.h"
+#include "util.h"
void test_hashmap_funcs(void);
void test_ordered_hashmap_funcs(void);
diff --git a/src/test/test-install.c b/src/test/test-install.c
index 359b262347..ef6f1efb89 100644
--- a/src/test/test-install.c
+++ b/src/test/test-install.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <stdio.h>
+#include <string.h>
#include "install.h"
diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c
index af0d76e894..75ce3a349e 100644
--- a/src/test/test-job-type.c
+++ b/src/test/test-job-type.c
@@ -22,8 +22,8 @@
#include <stdio.h>
#include "job.h"
-#include "unit.h"
#include "service.h"
+#include "unit.h"
int main(int argc, char*argv[]) {
JobType a, b, c, ab, bc, ab_c, bc_a, a_bc;
diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c
index 9765075365..427c698d1d 100644
--- a/src/test/test-locale-util.c
+++ b/src/test/test-locale-util.c
@@ -19,8 +19,8 @@
#include "locale-util.h"
-#include "strv.h"
#include "macro.h"
+#include "strv.h"
static void test_get_locales(void) {
_cleanup_strv_free_ char **locales = NULL;
diff --git a/src/test/test-log.c b/src/test/test-log.c
index 9dcfa2f274..a01df9b049 100644
--- a/src/test/test-log.c
+++ b/src/test/test-log.c
@@ -22,9 +22,9 @@
#include <stddef.h>
#include <unistd.h>
+#include "formats-util.h"
#include "log.h"
#include "util.h"
-#include "formats-util.h"
int main(int argc, char* argv[]) {
diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c
index e3e5a95add..556938a0f8 100644
--- a/src/test/test-loopback.c
+++ b/src/test/test-loopback.c
@@ -19,11 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <stdio.h>
+#include <string.h>
-#include "loopback-setup.h"
#include "log.h"
+#include "loopback-setup.h"
int main(int argc, char* argv[]) {
int r;
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 3050be9e9d..1175114a3a 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -22,8 +22,8 @@
#include <stdlib.h>
#include <unistd.h>
-#include "namespace.h"
#include "log.h"
+#include "namespace.h"
int main(int argc, char *argv[]) {
const char * const writable[] = {
diff --git a/src/test/test-ratelimit.c b/src/test/test-ratelimit.c
index 462b55cdb3..990b834c79 100644
--- a/src/test/test-ratelimit.c
+++ b/src/test/test-ratelimit.c
@@ -19,9 +19,9 @@
#include <unistd.h>
+#include "macro.h"
#include "ratelimit.h"
#include "time-util.h"
-#include "macro.h"
static void test_ratelimit_test(void) {
int i;
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index ebc9110c4d..8396ae60f3 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -21,8 +21,8 @@
#include <sched.h>
-#include "manager.h"
#include "macro.h"
+#include "manager.h"
int main(int argc, char *argv[]) {
Manager *m = NULL;
diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c
index 2402da6a6f..c20be99350 100644
--- a/src/test/test-siphash24.c
+++ b/src/test/test-siphash24.c
@@ -19,23 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "siphash24.h"
+#include "util.h"
#define ITERATIONS 10000000ULL
-/* see https://131002.net/siphash/siphash.pdf, Appendix A */
-int main(int argc, char *argv[]) {
+static int do_test(const uint8_t *in, size_t len, const uint8_t *key) {
struct siphash state = {};
- const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e };
- const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
uint64_t out = 0;
unsigned i, j;
- siphash24((uint8_t *)&out, in, sizeof(in), key);
- assert_se(out == htole64(0xa129ca6149be45e5));
+ out = siphash24(in, len, key);
+ assert_se(out == 0xa129ca6149be45e5);
/* verify the internal state as given in the above paper */
siphash24_init(&state, key);
@@ -43,13 +38,13 @@ int main(int argc, char *argv[]) {
assert_se(state.v1 == 0x6b617f6d656e6665);
assert_se(state.v2 == 0x6b7f62616d677361);
assert_se(state.v3 == 0x7b6b696e727e6c7b);
- siphash24_compress(in, sizeof(in), &state);
+ siphash24_compress(in, len, &state);
assert_se(state.v0 == 0x4a017198de0a59e0);
assert_se(state.v1 == 0x0d52f6f62a4f59a4);
assert_se(state.v2 == 0x634cb3577b01fd3d);
assert_se(state.v3 == 0xa5224d6f55c7d9c8);
- siphash24_finalize((uint8_t*)&out, &state);
- assert_se(out == htole64(0xa129ca6149be45e5));
+ out = siphash24_finalize(&state);
+ assert_se(out == 0xa129ca6149be45e5);
assert_se(state.v0 == 0xf6bcd53893fecff1);
assert_se(state.v1 == 0x54b9964c7ea0d937);
assert_se(state.v2 == 0x1b38329c099bb55a);
@@ -57,14 +52,34 @@ int main(int argc, char *argv[]) {
/* verify that decomposing the input in three chunks gives the
same result */
- for (i = 0; i < sizeof(in); i++) {
- for (j = i; j < sizeof(in); j++) {
+ for (i = 0; i < len; i++) {
+ for (j = i; j < len; j++) {
siphash24_init(&state, key);
siphash24_compress(in, i, &state);
siphash24_compress(&in[i], j - i, &state);
- siphash24_compress(&in[j], sizeof(in) - j, &state);
- siphash24_finalize((uint8_t*)&out, &state);
- assert_se(out == htole64(0xa129ca6149be45e5));
+ siphash24_compress(&in[j], len - j, &state);
+ out = siphash24_finalize(&state);
+ assert_se(out == 0xa129ca6149be45e5);
}
}
+ return 0;
+}
+
+/* see https://131002.net/siphash/siphash.pdf, Appendix A */
+int main(int argc, char *argv[]) {
+ const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e };
+ const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ uint8_t in_buf[20];
+
+ /* Test with same input but different alignments. */
+ memcpy(in_buf, in, sizeof(in));
+ do_test(in_buf, sizeof(in), key);
+ memcpy(in_buf + 1, in, sizeof(in));
+ do_test(in_buf + 1, sizeof(in), key);
+ memcpy(in_buf + 2, in, sizeof(in));
+ do_test(in_buf + 2, sizeof(in), key);
+ memcpy(in_buf + 4, in, sizeof(in));
+ do_test(in_buf + 4, sizeof(in), key);
}
diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c
index 4308ddfb64..fb115ce4f3 100644
--- a/src/test/test-sleep.c
+++ b/src/test/test-sleep.c
@@ -21,10 +21,10 @@
#include <stdio.h>
-#include "util.h"
#include "log.h"
#include "sleep-config.h"
#include "strv.h"
+#include "util.h"
static void test_sleep(void) {
_cleanup_strv_free_ char
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index da27cde3da..aef992ee3c 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -36,6 +36,7 @@
#include "logs-show.h"
#include "mount.h"
#include "path.h"
+#include "rlimit-util.h"
#include "scope.h"
#include "service.h"
#include "slice.h"
@@ -43,13 +44,11 @@
#include "socket.h"
#include "swap.h"
#include "target.h"
+#include "test-tables.h"
#include "timer.h"
#include "unit-name.h"
#include "unit.h"
#include "util.h"
-#include "rlimit-util.h"
-
-#include "test-tables.h"
int main(int argc, char **argv) {
test_table(architecture, ARCHITECTURE);
diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c
index e940b5a204..84b448a095 100644
--- a/src/test/test-terminal-util.c
+++ b/src/test/test-terminal-util.c
@@ -18,8 +18,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdbool.h>
+#include <stdio.h>
#include "fd-util.h"
#include "fileio.h"
diff --git a/src/test/test-time.c b/src/test/test-time.c
index 820e4aaee2..8896b2c92b 100644
--- a/src/test/test-time.c
+++ b/src/test/test-time.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "time-util.h"
#include "strv.h"
+#include "time-util.h"
static void test_parse_sec(void) {
usec_t u;
diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c
index 1754d06b2d..b18b3fca0e 100644
--- a/src/test/test-unaligned.c
+++ b/src/test/test-unaligned.c
@@ -17,8 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unaligned.h"
#include "sparse-endian.h"
+#include "unaligned.h"
#include "util.h"
static uint8_t data[] = {
@@ -26,7 +26,7 @@ static uint8_t data[] = {
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
};
-int main(int argc, const char *argv[]) {
+static void test_be(void) {
uint8_t scratch[16];
assert_se(unaligned_read_be16(&data[0]) == 0x0001);
@@ -91,3 +91,75 @@ int main(int argc, const char *argv[]) {
unaligned_write_be64(&scratch[7], 0x0708090a0b0c0d0e);
assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0);
}
+
+static void test_le(void) {
+ uint8_t scratch[16];
+
+ assert_se(unaligned_read_le16(&data[0]) == 0x0100);
+ assert_se(unaligned_read_le16(&data[1]) == 0x0201);
+
+ assert_se(unaligned_read_le32(&data[0]) == 0x03020100);
+ assert_se(unaligned_read_le32(&data[1]) == 0x04030201);
+ assert_se(unaligned_read_le32(&data[2]) == 0x05040302);
+ assert_se(unaligned_read_le32(&data[3]) == 0x06050403);
+
+ assert_se(unaligned_read_le64(&data[0]) == 0x0706050403020100);
+ assert_se(unaligned_read_le64(&data[1]) == 0x0807060504030201);
+ assert_se(unaligned_read_le64(&data[2]) == 0x0908070605040302);
+ assert_se(unaligned_read_le64(&data[3]) == 0x0a09080706050403);
+ assert_se(unaligned_read_le64(&data[4]) == 0x0b0a090807060504);
+ assert_se(unaligned_read_le64(&data[5]) == 0x0c0b0a0908070605);
+ assert_se(unaligned_read_le64(&data[6]) == 0x0d0c0b0a09080706);
+ assert_se(unaligned_read_le64(&data[7]) == 0x0e0d0c0b0a090807);
+
+ zero(scratch);
+ unaligned_write_le16(&scratch[0], 0x0100);
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint16_t)) == 0);
+ zero(scratch);
+ unaligned_write_le16(&scratch[1], 0x0201);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint16_t)) == 0);
+
+ zero(scratch);
+ unaligned_write_le32(&scratch[0], 0x03020100);
+
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_le32(&scratch[1], 0x04030201);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_le32(&scratch[2], 0x05040302);
+ assert_se(memcmp(&scratch[2], &data[2], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_le32(&scratch[3], 0x06050403);
+ assert_se(memcmp(&scratch[3], &data[3], sizeof(uint32_t)) == 0);
+
+ zero(scratch);
+ unaligned_write_le64(&scratch[0], 0x0706050403020100);
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[1], 0x0807060504030201);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[2], 0x0908070605040302);
+ assert_se(memcmp(&scratch[2], &data[2], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[3], 0x0a09080706050403);
+ assert_se(memcmp(&scratch[3], &data[3], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[4], 0x0B0A090807060504);
+ assert_se(memcmp(&scratch[4], &data[4], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[5], 0x0c0b0a0908070605);
+ assert_se(memcmp(&scratch[5], &data[5], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[6], 0x0d0c0b0a09080706);
+ assert_se(memcmp(&scratch[6], &data[6], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_le64(&scratch[7], 0x0e0d0c0b0a090807);
+ assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0);
+}
+
+int main(int argc, const char *argv[]) {
+ test_be();
+ test_le();
+}
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index c3973a316e..0b3630f77c 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -680,11 +680,42 @@ static void test_config_parse_rlimit(void) {
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
+
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ /* Invalid values don't change rl */
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
@@ -697,6 +728,11 @@ static void test_config_parse_rlimit(void) {
assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_CPU]);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
+ assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
+
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
@@ -714,16 +750,31 @@ static void test_config_parse_rlimit(void) {
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
+
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
+
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c
index 0af8349732..e98be5763c 100644
--- a/src/test/test-utf8.c
+++ b/src/test/test-utf8.c
@@ -20,9 +20,9 @@
***/
#include "alloc-util.h"
+#include "string-util.h"
#include "utf8.h"
#include "util.h"
-#include "string-util.h"
static void test_utf8_is_printable(void) {
assert_se(utf8_is_printable("ascii is valid\tunicode", 22));
diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c
index 2e5d0c3aae..d10d9f49af 100644
--- a/src/test/test-watchdog.c
+++ b/src/test/test-watchdog.c
@@ -21,8 +21,8 @@
#include <unistd.h>
-#include "watchdog.h"
#include "log.h"
+#include "watchdog.h"
int main(int argc, char *argv[]) {
usec_t t = 10 * USEC_PER_SEC;
diff --git a/src/timesync/timesyncd-conf.h b/src/timesync/timesyncd-conf.h
index 56466fe462..cbc19c4054 100644
--- a/src/timesync/timesyncd-conf.h
+++ b/src/timesync/timesyncd-conf.h
@@ -22,7 +22,6 @@
***/
#include "conf-parser.h"
-
#include "timesyncd-manager.h"
const struct ConfigPerfItem* timesyncd_gperf_lookup(const char *key, unsigned length);
diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h
index 090b2fcba8..fab22cfe84 100644
--- a/src/timesync/timesyncd-manager.h
+++ b/src/timesync/timesyncd-manager.h
@@ -22,8 +22,9 @@
***/
#include "sd-event.h"
-#include "sd-resolve.h"
#include "sd-network.h"
+#include "sd-resolve.h"
+
#include "list.h"
#include "ratelimit.h"
diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h
index 18c44445e1..f764d0737b 100644
--- a/src/timesync/timesyncd-server.h
+++ b/src/timesync/timesyncd-server.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "socket-util.h"
#include "list.h"
+#include "socket-util.h"
typedef struct ServerAddress ServerAddress;
typedef struct ServerName ServerName;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 74b6b91593..f9a759e223 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1226,8 +1226,28 @@ static int create_item(Item *i) {
mkdir_parents_label(i->path, 0755);
if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
- RUN_WITH_UMASK((~i->mode) & 0777)
- r = btrfs_subvol_make(i->path);
+
+ if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0)
+
+ /* Don't create a subvolume unless the
+ * root directory is one, too. We do
+ * this under the assumption that if
+ * the root directory is just a plain
+ * directory (i.e. very light-weight),
+ * we shouldn't try to split it up
+ * into subvolumes (i.e. more
+ * heavy-weight). Thus, chroot()
+ * environments and suchlike will get
+ * a full brtfs subvolume set up below
+ * their tree only if they
+ * specifically set up a btrfs
+ * subvolume for the root dir too. */
+
+ r = -ENOTTY;
+ else {
+ RUN_WITH_UMASK((~i->mode) & 0777)
+ r = btrfs_subvol_make(i->path);
+ }
} else
r = 0;
diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c
index 67b750c4b3..462fab7623 100644
--- a/src/udev/mtd_probe/mtd_probe.c
+++ b/src/udev/mtd_probe/mtd_probe.c
@@ -17,14 +17,14 @@
* Boston, MA 02110-1301 USA
*/
+#include <fcntl.h>
+#include <mtd/mtd-user.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/ioctl.h>
-#include <mtd/mtd-user.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <stdlib.h>
#include "mtd_probe.h"
diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c
index a007ccee2f..6a6c5522a7 100644
--- a/src/udev/mtd_probe/probe_smartmedia.c
+++ b/src/udev/mtd_probe/probe_smartmedia.c
@@ -17,15 +17,16 @@
* Boston, MA 02110-1301 USA
*/
+#include <fcntl.h>
+#include <mtd/mtd-user.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <mtd/mtd-user.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <stdint.h>
+
#include "mtd_probe.h"
static const uint8_t cis_signature[] = {
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 776674e994..77d9bf995a 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -354,14 +354,14 @@ static int get_mac(struct udev_device *device, bool want_random,
if (want_random)
random_bytes(mac->ether_addr_octet, ETH_ALEN);
else {
- uint8_t result[8];
+ uint64_t result;
- r = net_get_unique_predictable_data(device, result);
+ r = net_get_unique_predictable_data(device, &result);
if (r < 0)
return r;
assert_cc(ETH_ALEN <= sizeof(result));
- memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+ memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
}
/* see eth_random_addr in the kernel */
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 1e190140b2..aa18c7e420 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -593,31 +593,23 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path)
return parent;
}
-static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) {
- struct udev_device *scsi_dev;
+/* Handle devices of AP bus in System z platform. */
+static struct udev_device *handle_ap(struct udev_device *parent, char **path) {
+ const char *type, *func;
assert(parent);
- assert(dev);
assert(path);
- scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
- if (scsi_dev != NULL) {
- const char *wwpn;
- const char *lun;
- const char *hba_id;
-
- hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id");
- wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn");
- lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun");
- if (hba_id != NULL && lun != NULL && wwpn != NULL) {
- path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun);
- goto out;
- }
- }
+ type = udev_device_get_sysattr_value(parent, "type");
+ func = udev_device_get_sysattr_value(parent, "ap_functions");
- path_prepend(path, "ccw-%s", udev_device_get_sysname(parent));
+ if (type != NULL && func != NULL) {
+ path_prepend(path, "ap-%s-%s", type, func);
+ goto out;
+ }
+ path_prepend(path, "ap-%s", udev_device_get_sysname(parent));
out:
- parent = skip_subsystem(parent, "ccw");
+ parent = skip_subsystem(parent, "ap");
return parent;
}
@@ -629,13 +621,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
assert(dev);
- /* S390 ccw bus */
- parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
- if (parent != NULL) {
- handle_ccw(parent, dev, &path);
- goto out;
- }
-
/* walk up the chain of devices and compose path */
parent = dev;
while (parent != NULL) {
@@ -683,6 +668,25 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
parent = skip_subsystem(parent, "scm");
supported_transport = true;
supported_parent = true;
+ } else if (streq(subsys, "ccw")) {
+ path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent));
+ parent = skip_subsystem(parent, "ccw");
+ supported_transport = true;
+ supported_parent = true;
+ } else if (streq(subsys, "ccwgroup")) {
+ path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent));
+ parent = skip_subsystem(parent, "ccwgroup");
+ supported_transport = true;
+ supported_parent = true;
+ } else if (streq(subsys, "ap")) {
+ parent = handle_ap(parent, &path);
+ supported_transport = true;
+ supported_parent = true;
+ } else if (streq(subsys, "iucv")) {
+ path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent));
+ parent = skip_subsystem(parent, "iucv");
+ supported_transport = true;
+ supported_parent = true;
}
if (parent)
@@ -705,7 +709,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport)
path = mfree(path);
-out:
if (path != NULL) {
char tag[UTIL_NAME_SIZE];
size_t i;
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index bbda9de08c..3ebe36f043 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -18,9 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include "sd-login.h"
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 1e05be51a5..962de22f43 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -10,13 +10,13 @@
*/
#include <errno.h>
-#include <stdlib.h>
+#include <poll.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 9aa5ab185d..f1fdccaed8 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <errno.h>
-#include <stdio.h>
#include <dirent.h>
+#include <errno.h>
#include <stddef.h>
-#include <unistd.h>
+#include <stdio.h>
#include <sys/inotify.h>
+#include <unistd.h>
#include "udev.h"
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
index 78170463b6..989decbe95 100644
--- a/src/udev/udevadm-control.c
+++ b/src/udev/udevadm-control.c
@@ -13,15 +13,15 @@
*/
#include <errno.h>
+#include <getopt.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
#include <string.h>
#include <unistd.h>
-#include <getopt.h>
-#include "udev.h"
#include "udev-util.h"
+#include "udev.h"
static void print_help(void) {
printf("%s control COMMAND\n\n"
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index 30aa53feb2..f9cb5e63a2 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -15,15 +15,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
#include <errno.h>
-#include <signal.h>
#include <getopt.h>
-#include <time.h>
-#include <sys/time.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/epoll.h>
+#include <sys/time.h>
+#include <time.h>
#include "fd-util.h"
#include "formats-util.h"
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
index c25071b0fe..6a5dc6e9e4 100644
--- a/src/udev/udevadm-settle.c
+++ b/src/udev/udevadm-settle.c
@@ -17,14 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <poll.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "parse-util.h"
#include "udev.h"
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 5364b92a57..6d9d765153 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -191,7 +191,7 @@ static void worker_free(struct worker *worker) {
assert(worker->manager);
- hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
+ hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
udev_monitor_unref(worker->monitor);
event_free(worker->event);
@@ -234,7 +234,7 @@ static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor
if (r < 0)
return r;
- r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
+ r = hashmap_put(manager->workers, PID_TO_PTR(pid), worker);
if (r < 0)
return r;
@@ -891,7 +891,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
}
/* lookup worker who sent the signal */
- worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
+ worker = hashmap_get(manager->workers, PID_TO_PTR(ucred->pid));
if (!worker) {
log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
continue;
@@ -1195,7 +1195,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
if (pid <= 0)
break;
- worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
+ worker = hashmap_get(manager->workers, PID_TO_PTR(pid));
if (!worker) {
log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
continue;
diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
index 607d78a019..aec6676a33 100644
--- a/src/udev/v4l_id/v4l_id.c
+++ b/src/udev/v4l_id/v4l_id.c
@@ -13,17 +13,17 @@
* General Public License for more details:
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <linux/videodev2.h>
#include "fd-util.h"